Start a headless run with a cost ceiling and a timeout, ask read-only questions, schedule turns, and know what stops each one.
Written for
v0.8.0
Works in
Terminal · Desktop alpha
Basis
Recorded session
Updated
A headless run: JSON events to a file, exit status 0, the answer, and the run_end event that closes the stream. Terminal · v0.8.0Recording · 0:18Transcript
An unattended CLIO Coder run with JSON output
Recorded with CLIO Coder 0.8.0. Each section is the terminal screen at that moment.
== answer
~/projects/calibration-lab $ clio-coder run --json "Run the test check and report how many tests pass." > run.jsonl; echo "exit $?"
exit 0
~/projects/calibration-lab $ jq -r 'select(.type == "turn_end").message.content[] | select(.type == "text").text' run.jsonl
Test check finished: **6 of 7 pass, 1 fails.**
The failing test is `absolute zero: 0 K = -273.15°C = -459.67°F` at `calibration.test.mjs:20`. It throws `RangeError: Kelvin temperature 0 is below absolute zero (0 K)` from `kelvinToCelsius` at `temperature.mjs:22` — the guard rejects `0 K` even though 0 K is absolute zero itself and the test expects it to be valid.
All six other tests pass, including the `rejects temperatures below absolute zero with RangeError` case, so the boundary condition is off-by-one: `0 K` should be allowed.
~/projects/calibration-lab $
== run-end
s." > run.jsonl; echo "exit $?"
exit 0
~/projects/calibration-lab $ jq -r 'select(.type == "turn_end").message.content[] | select(.type == "text").text' run.jsonl
Test check finished: **6 of 7 pass, 1 fails.**
The failing test is `absolute zero: 0 K = -273.15°C = -459.67°F` at `calibration.test.mjs:20`. It throws `RangeError: Kelvin temperature 0 is below absolute zero (0 K)` from `kelvinToCelsius` at `temperature.mjs:22` — the guard rejects `0 K` even though 0 K is absolute zero itself and the test expects it to be valid.
All six other tests pass, including the `rejects temperatures below absolute zero with RangeError` case, so the boundary condition is off-by-one: `0 K` should be allowed.
~/projects/calibration-lab $ tail -n 1 run.jsonl | jq .
{
"type": "run_end",
"startedAt": "2026-11-13T00:18:10.188Z",
"endedAt": "2026-11-13T00:18:16.582Z",
"exitCode": 0,
"outcome": "succeeded",
"safety": {
"decisions": {
"allowed": 1,
"blocked": 0,
"permissionRequested": 0
},
"blockedAttempts": []
}
}
~/projects/calibration-lab $
You can start a task and leave. Headless clio-coder run does one turn with nobody attached, and the limits you set are enforced. This guide covers a bounded headless run, a read-only one, the timeouts that apply when you walk away from an open session, and scheduled turns.
Before you start
CLIO Coder installed, with a connected model.
A Git repository, and a task you can state completely in one prompt.
01
Put your decisions in the prompt
The judge reads only your prompt in a headless run, so name the actions the job needs:
Shell
clio-coder run --max-cost-usd 2 --timeout 1800 \
"Fix the failing parser test, run the test check, and commit on this branch. Do not push."
--max-cost-usd caps the priced spend this run adds. Reaching it stops the run and its workers with exit 4 and budget_ceiling. Calls already in flight can pass the cap, and unpriced routes cannot be bounded, so pair it with --timeout, which exits 124 on expiry. The session ceiling, 5 USD by default, still applies.
02
Ask a question that cannot change anything
Shell
clio-coder run --read-only "Which modules have no tests? Report paths."
--read-only is an enforced ceiling on the main agent, not a request. No file outside CLIO Coder's home changes: writes are refused, and shell commands run only in a read-only sandbox.
03
Stream it to another program
Shell
clio-coder run --json "Summarize the last five commits."
The stream opens with a session header carrying its schema version and ends with one run_end frame carrying the exit code and outcome. Read the result from that frame. Continue later with --continue or --session <id prefix>.
04
Walk away from an open session
In the terminal, an unanswered approval card is denied after safety.unattendedAfterSeconds (300 by default) and the turn continues. A question takes its recommended option. Any key stops the countdown. When you return, /decisions shows what was chosen, and the exit summary counts it on an Unattended line.
05
Schedule turns while idle
/loop 30m Check the nightly build log and report anything new.
/loop 5m --command make check
/loop
A bare /loop lists the jobs. A loop runs only while its conversation is idle and never replays missed runs. The --command form polls a program directly, with no shell.
What you should see
A finished turn with its exit code, not a parked prompt. An exit of 4 means the cost ceiling stopped it. clio-coder telemetry why-stopped <session> explains a stop afterward.
Read how a run ended
Stderr names the session and ends with an observed: line that counts tool calls, refusals, writes, and checks. When --max-cost-usd meets a route with no price, stderr says the cap cannot bound it; declare targets[].pricing to fix that. A script should read the exit code or the run_end frame, not the prose answer.
In a separate run of the first step, made for this guide apart from the session at the top of the page, Qwen 3.8 27B worked on a repository with one failing parser test. It fixed the parser, ran the test, committed on the branch, and pushed nothing. Stderr read:
clio-coder run: --max-cost-usd does not bound unpriced routes: litellm/qwen3.8-27b; declare targets[].pricing to bound them
clio-coder run: session sjajclvyg6cw
clio-coder run: observed: 10 tool calls, 0 refused · 1 write · checks passed: npm run test, git diff
A --json run of the third step from the same set ended with this frame:
It failed: the model was unreachable, a worker did not deliver, or a refused call left the task undone
2
A usage error, including --autonomy yolo as root outside a container
3
At yolo, the safety judge blocked too many calls in a row; review the run, then --continue
4
A cost ceiling, or at yolo an autonomous cap on tool calls, minutes, or tokens, stopped it; --continue resumes
124
--timeout expired; the run still settled and sealed
130, 143
Ctrl+C or a SIGTERM stopped it
Pick the right tool
When you want
Use
What still stops it
One bounded task
clio-coder run at default
Judge, sandbox, cost ceiling, timeout
A long job you leave running
clio-coder run --autonomy yolo
Contained by default: the sandbox and judge stay on, and a call the judge does not allow is refused back to the run. Ceilings, timeout, the loop guard, and the tool budget also stop it
A recurring check
/loop in an open session
Pause or stop it; needs the session to stay open
Boundaries
A contained command starts without credential variables and cannot open secret files, so name tools that need them. CLIO Coder may rerun with unsandboxed: true, which the judge reviews. At unconfined yolo under safety.sandbox: required, that retry is refused.
yolo does not carry over from settings.yaml to a headless run. It comes only from that run's own --autonomy yolo, and it exits 2 as root outside a detected container.