Headless with ari -p
Run one turn and exit, stream the event schema with --json, take a prompt from stdin, and branch on the exit code in CI.
ari -p runs a single turn and exits, using the same core, loop, tools, permission pipeline, and ledger the TUI drives. It is the way to put ari in a script or a CI job.
One turn, then exit
ari -p "read main.go and summarize it"
ari runs the turn, prints the assistant's final text, and exits. No TUI, no session you have to quit.
A prompt from stdin
Pass - as the prompt to read it from standard input, so ari composes in a pipeline:
git log -1 --format=%B | ari -p -
echo "summarize the build failure" | ari -p -
Stream the events with --json
--json streams the raw event schema instead of prose: a hello frame first, then the turn's events. A downstream step can reconstruct the transcript, or resume from a sequence cursor.
ari -p --json "list the exported functions in this package"
Each line is one event with a monotonic sequence number, so a consumer can detect a gap and knows it saw the whole turn.
Modes in headless
When there is no human to ask, a turn that would need approval is denied, not queued and not silently allowed, so a CI run never stalls on a dialog. To let a headless run make changes, choose the mode on purpose:
# edits without prompts, commands still denied at the ask stage
ari -p --mode auto-edit "fix the failing test in ./parser"
# fully unattended; the safety floor still holds
ari -p --json --mode full-auto \
"rename Greeting to Greet across the package, then run go test"
The exit code is the contract
The process exit code is the turn's terminal reason, so a CI step can branch without parsing output:
| Code | Meaning |
|---|---|
| 0 | ok |
| 1 | internal error |
| 2 | config error |
| 3 | nest error |
| 4 | provider error |
| 5 | permission denied |
| 6 | budget exceeded |
| 7 | canceled |
A run that was blocked by the permission pipeline exits 5, so a job that expected an unattended change can tell "the model declined" from "ari was not allowed to". ari doctor uses a separate contract for its own audit result; see the doctor reference.
A CI job
- name: Let ari take a pass
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
ari -p --json --mode full-auto \
"apply the TODO in ./parser and run go test ./..." \
| tee turn.jsonl
The key is an environment reference the job provides, ari keeps it out of the streamed events, and the exit code decides whether the step passed.