<!-- Markdown mirror. Canonical: https://empryo.com/docs/recipes/headless -->

# Run from CI or scripts

> Run Empryo without the TUI for scripts and CI: pipe a prompt, stream JSON or JSONL events, resume sessions, and cap runs with max-steps and timeout flags.

Headless mode runs Empryo without the TUI. Same agent, same tools, no renderer. For scripts, CI pipelines, automation.

## Basics

```bash
# Inline prompt
empryo --headless "explain the auth middleware"

# From stdin
echo "find unused exports" | empryo --headless

# JSON output
empryo --headless --json "list all TODOs"

# Real-time event stream
empryo --headless --events "refactor the store"
```

Agent text streams to `stdout`. Progress messages go to `stderr` so piping stays clean.

## Useful flags

| Flag | What it does |
|------|-------------|
| `--model <id>` | Override the default model |
| `--max-steps <n>` | Stop after N steps |
| `--timeout <ms>` | Kill after N ms |
| `--system "..."` | Add custom system instructions |
| `--include <file>` | Pre-load a file into context (repeatable) |
| `--no-genome` | Skip the startup scan (faster for quick questions) |
| `--diff` | List files changed after the run |
| `--save-session` | Save conversation so you can resume later |
| `--session <id>` | Resume a saved session |
| `--chat` | Interactive multi-turn chat |
| `--proxy-quota` | Print [proxy subscription limits](/docs/providers/proxy) and exit (no agent turn) |
| `--review [brief]` | Judge what changed and exit on the verdict, instead of running a turn ([the reviewer](/docs/agents/review)) |
| `--quiet` | Suppress stderr progress |

Exit codes: `0` success, `1` error, `2` timeout, `130` abort. `--review` adds `3` for FAIL and `4` for PARTIAL.

## Gate a pipeline on a verdict

```bash
# 0 = PASS or clean tree, 3 = FAIL, 4 = PARTIAL
empryo --headless --review "check the migration for data loss" --quiet
```

A fresh agent reads the files that changed, with no transcript to inherit an opinion from. A clean tree exits 0 without calling a model.

## CI example

```yaml
# .github/workflows/lint.yml
- name: Auto-fix lint
  run: |
    empryo --headless --max-steps 30 --timeout 180000 --diff \
      "run the linter, fix every issue, typecheck"
```

## Resume a session

```bash
# step 1: investigate
empryo --headless --save-session "analyze the auth module, find all issues"

# grab the session id from the output, then:
empryo --headless --session <id> --save-session "now fix them"
empryo --headless --session <id> "write tests"
```

## Parse events

```bash
empryo --headless --events "refactor the store" | while read -r line; do
  type=$(echo "$line" | jq -r '.type')
  case "$type" in
    tool-call) echo "→ $(echo "$line" | jq -r '.tool')" ;;
    done)      echo "done in $(echo "$line" | jq -r '.duration')ms" ;;
  esac
done
```

Event types: `start`, `text`, `tool-call`, `tool-result`, `step`, `error`, `done`, `session-saved`.

## What's disabled

- TUI, editor panel, splash screen.
- Interactive approvals - destructive actions auto-allow in headless mode.
- User steering - no stdin during the run.

## Security in CI

Set `EMPRYO_NO_GENOME=1` to skip the startup scan on tiny CI jobs. Store API keys as CI secrets. Use `--max-steps` and `--timeout` to cap runaway runs.
