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.
Copy & share
Loading sections…
Connect MCP or install the Empryo skillSection exports contain only that heading’s content. Markdown and text links fetch the selected content directly, without the rest of the page.
--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", "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) |
cache-miss | reason, readTokens, writtenTokens — the prompt cache missed and roughly what re-writing the prefix cost |
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.