Headless & output formats
The contract for empryo --headless: plain, JSON, and JSONL event output shapes, multi-turn chat over stdin, exit codes, and what the runner disables.
--headless runs the same agent with no terminal UI — for scripts, CI, and automation. This page is the output contract; for end-to-end patterns see the CI recipe.
empryo --headless "explain the auth middleware"
echo "find unused exports" | empryo --headless # prompt from stdinAssistant text streams to stdout; progress (model, tools, footer) goes to stderr, so pipes stay clean. Output is one of three shapes.
Plain (default)
Assistant text streams straight to stdout. When stdout is a TTY it is Markdown-rendered; piped, it is raw text. Force either way with --render / --no-render. Add --quiet to drop the stderr progress lines, or --diff to print the changed files at the end.
JSON — --json
One pretty-printed object after the run completes. No streaming.
{
"model": "anthropic/claude-opus-4-8",
"mode": "default",
"prompt": "list all TODOs",
"output": "…assistant's final answer…",
"steps": 7,
"tokens": { "input": 18432, "output": 1204, "cacheRead": 16000 },
"toolCalls": ["grep", "read", "genome_find"],
"filesEdited": ["src/auth/session.ts"],
"duration": 38211
}The error key is present only on failure.
Events — --events
A JSONL stream: one JSON object per line, emitted in real time. Each has a type:
| Event | Payload |
|---|---|
start | model, mode, session, genome (files/symbols or null), workers |
text | content — an assistant text delta |
tool-call | tool, toolCallId, input |
tool-result | tool, toolCallId, summary (truncated to 200 chars) |
step | step, tokens (cumulative + last-step input/output/cacheRead) |
warning | message |
error | error |
done | output, steps, tokens, toolCalls, filesEdited, duration |
session-saved | sessionId (only with --save-session) |
empryo --headless --events "refactor the store" | while read -r line; do
case "$(jq -r .type <<<"$line")" in
tool-call) echo "→ $(jq -r .tool <<<"$line")" ;;
done) echo "done in $(jq -r .duration <<<"$line")ms" ;;
esac
doneChat — --chat
A multi-turn REPL over stdin. Each line is a turn; a trailing \ continues to the next line; a blank line is skipped. --json and --events apply per turn. On exit (EOF or Ctrl+C) the session is auto-saved and a resume hint is printed.
empryo --headless --chat <<'EOF'
what does the session store do?
now add a TTL field to it
EOFChat mode emits ready before each prompt, turn-done per turn, and chat-done at the end.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Error |
2 | Timeout (--timeout fired) |
130 | Aborted (SIGINT) |
What headless disables
- The TUI, editor panel, and splash screen.
- Interactive approvals — destructive actions auto-allow.
- User steering — there is no live stdin during a run (except
--chat).
On small CI jobs, EMPRYO_NO_GENOME=1 (or --no-genome) skips the startup scan for a faster cold start. Cap runaway runs with --max-steps and --timeout.