Quickstart
From a repository with no manifest to a first ciresk ci check in five minutes.
Every command on this page is ciresk ci <command>. This page assumes the CLI is installed and logged in; if not, start with Install the CLI.
What you need
| Item | Detail |
|---|---|
| An organization with Ciresk CI | Sign in at platform.ciresk.com (the sign-in page also creates an account) and start your own organization. Ciresk turns CI on per organization: write to [email protected] with your organization's name. Until then ciresk ci auth login answers that none of your organizations has ci enabled. |
| A folder with code in it | git is optional: with an origin remote the repository is identified by its URL, otherwise the first run registers the folder as local/<folder name> and writes that slug to .ciresk/repo; commit the file so every clone runs as the same repository. The repository registers itself on its first run; private repositories work the same, since the CLI uploads the working tree. |
| A credential | A person logs in with ciresk ci auth login. A machine or an agent sandbox exports CIRESK_TOKEN with a csk_live_eu_... token from platform.ciresk.com under API tokens and runs ciresk ci --pass-token .... See API keys. |
| Workers | Tasks run on workers that belong to your organization: a Linux host, a PC under WSL2 or a cloud instance running ciresk-ci-worker, enrolled with ciresk ci workers add. Without an online worker a job stays queued; ciresk ci doctor says so and ciresk ci status <job> names the reason. See Run your own worker. |
Check the set-up before the first run:
ciresk ci doctorEvery line is ok or fix with the command that repairs it, and the last line is the next command to run.
Create the manifest
ciresk ci initinit writes .ciresk/ci.yaml with check and test for the toolchain it detects, and lint where it finds a linter (clippy for Rust; a lint script or an eslint config for JavaScript). For Rust it also writes .config/nextest.toml, which makes nextest write the JUnit file the test task reports. A package.json gets the package manager its packageManager field names, else the one whose lockfile is there, else npm. Edit the files and commit them; the full reference is Manifest. For a single Rust crate init writes this (without the comments it adds):
version: 1
toolchains:
"cargo:cargo-nextest": "0.9.148"
rust: "1.95.0"
globals:
inputs: [".config/nextest.toml", ".ciresk/*.sh"]
env: { CI: "true" }
pass_env: []
workspace:
warm: true
keep: ["target"]
tasks:
check:
run: "cargo check --all-targets"
inputs: ["src/**", "Cargo.toml"]
affected: { strategy: cargo, targets_arg: "-p {crate}" }
timeout: "10m"
test:
run: "cargo nextest run"
inputs: ["src/**", "Cargo.toml"]
affected: { strategy: cargo, targets_arg: "-p {crate}" }
timeout: "10m"
report: { junit: "target/nextest/default/junit.xml" }
lint:
run: "cargo clippy --all-targets -- -D warnings"
inputs: ["src/**", "Cargo.toml"]
affected: { strategy: cargo, targets_arg: "-p {crate}" }
timeout: "10m"ciresk ci lint runs the lint task. Every tool a run line calls comes from toolchains: cargo nextest works because of the cargo:cargo-nextest entry. For Node, the TypeScript example is the pnpm version to start from.
Run a check
ciresk ci check --followcheck runs the check task on your working tree (on the targets you pass with -p, else the whole run command), waits and prints the summary. --follow streams the task's log to stderr while it runs.
tree: 612 entries, 1,070,702 bytes, root 1d6ccb175d0e; walk 9 ms, hashed 0 (reused 612) 1 ms, plan 0 ms: 0 blobs, 0 bytes: 0 inline bodies, 0 presigned puts, 0 multipart parts
timings: locate 4 ms, index 1 ms, walk 9 ms, hash 1 ms, plan 0 ms, upload 0 ms, submit 41 ms
budget: session 1296/72000 units, day 1296/720000, resets 00:00Z
job_01a158eea7347770a076e6b4ab7955d9: queued
job_01a158eea7347770a076e6b4ab7955d9: leased
job_01a158eea7347770a076e6b4ab7955d9: running
[ciresk] toolchains installed with mise in 45.9s
[ciresk] running `cargo check --all-targets` in .
[ciresk] exit Some(0)
job_01a158eea7347770a076e6b4ab7955d9: succeeded
succeeded job_01a158eea7347770a076e6b4ab7955d9 check@main 8m 19s 14080 units cache 0 hit / 1 miss / 0 write
trust: trusted_interactive (warm workspace, read-write cache)
next: ciresk ci status job_01a158eea7347770a076e6b4ab7955d9With ciresk ci watch running, the tree: line reads tree: watcher live, nothing to upload. Progress, the timings and the budget line go to stderr; the data goes to stdout. With --json, stdout is exactly one JSON document.
Read the result
The exit code is the verdict: 0 is a pass, 1 is a failed task or test, and 2 to 8 name a reason that is not a code failure (usage, auth, policy, budget, cancelled, timed out, infrastructure). The full table is in Exit codes. A failed task ends with the failing tests, the last lines of the first failed task and the next command:
failed job_01a158e79d4874dcb4d5ca3a263a7f9f test@main 1m 12s 960 units cache 1 hit / 1 miss / 0 write
trust: trusted_interactive (warm workspace, read-write cache)
tasks:
test: failed, exit 1, 1m 8s
failing tests: 1
FAIL manifest::parses_nested_manifests
assertion `left == right` failed
tail of test (last 3 lines):
test manifest::parses_nested_manifests ... FAILED
error: test run failed
[ciresk] exit Some(1)
next: ciresk ci tests job_01a158e79d4874dcb4d5ca3a263a7f9fHuman output ends with the exact command for the obvious drill-down, and every --json envelope carries it as next:
| After | next |
|---|---|
| A failed test run | ciresk ci tests <job>: failing tests first, with file:line and the first message lines. |
| A failed task | ciresk ci logs <job> --task check (failed-only by default): the last 200 lines, at most 256 KiB. |
| A passed job | ciresk ci status <job>. |
| More than 50 failing tests | ciresk ci tests <job> --cursor eyJ.... |
A job still running without --wait | ciresk ci wait <job>. |
Run next rather than ask for a whole log: logs returns failed-only, the last 200 lines, at most 256 KiB per call, and says in band when it truncated.
After the first run
| Want | Command |
|---|---|
| Tests for one crate or package | ciresk ci test -p <crate> |
| What would be uploaded, without uploading it | ciresk ci run check --dry-run |
| Every run one request | ciresk ci watch in a second terminal, or ciresk ci watch --once at session start |
| A job in the background, then wait | export CIRESK_JOB=$(ciresk ci run test --json | jq -r .data.id); ciresk ci wait |
| Your spend and limits | ciresk ci budget; see Limits and spend |
| Claude Code, Codex and Cursor set-up, the hooks, MCP | Claude Code, Codex, Cursor |
| The same check in GitHub Actions, no secret | GitHub Actions |
| Run your own workers | Run your own worker |
| Delete a repository's data, or leave | Leaving Ciresk CI |
Limits and spend
Every job is metered in units, and every response carries the budget line you saw above: the units spent in this session and today against the caps, and the time the day resets (00:00 UTC). A new organization starts with these caps:
| Cap | Default |
|---|---|
| Units per session | 72,000 (a soft budget at 36,000 runs further jobs at a lower priority) |
| Units per day, per person or agent | 720,000 (soft at 360,000) |
| Units per job | 36,000 |
| Jobs per session, per day | 200, 2,000 |
A job that would pass a hard cap is refused with exit code 5 and the time the window resets. ciresk ci budget prints where you stand, ciresk ci policy get every limit with its source, and an organization admin changes one with ciresk ci policy set hard_units_per_day=50000. Usage per month, and a monthly budget once a unit price is set for your organization, are on platform.ciresk.com under Billing.
Good to know
- A folder that was never
git init-ed works the same: the first run registers it under a slug of its own and uploads the tree once; from the second run only changed files travel. See Caching and tree sync. - Identical requests from two people or two agents are one job, and a retry after a timeout returns the same job. See How it works.
- A job started inside Claude Code or Codex is attributed to
agent:claude-codeoragent:codex. The actor is attribution only: the trust tier comes from your credential, the ref and your policy, and a policy withagent_branches_untrusted=truerunsagent:*jobs asuntrusted.CIRESK_ACTORor--actoroverrides the detected actor.