Get updates
Recipe

Run an agent harness unattended in CI

Job: a scheduled or CI run that does one task, touches only what it should, and prints output a script can parse. Each harness has a headless mode; their safe defaults differ a lot.

Checked against official docs on Oct 18, 20269 sourcesNo affiliate links

Headless commands at a glance

HarnessCommandMachine outputLeast-privilege default
Codex CLIcodex exec "…"--json (JSONL), -o file for the final messageRead-only sandbox unless you pass --sandbox workspace-write
Claude Codeclaude -p "…"--output-format json (includes total_cost_usd)--permission-mode dontAsk denies anything not pre-approved
OpenCodeopencode run "…"--format jsonConfig-driven; most tools default to allow, so set permission
goosegoose run --recipe r.yamlrecipe response.json_schemaCap the loop with --max-turns
Gemini CLIgemini -p "…"--output-format json or stream JSON—
Aideraider --message "…" file—Edits only the files you name

Codex

Fix lint errors, write the summary to a file
codex exec --sandbox workspace-write \
  -o summary.md \
  "Run npm run lint, fix the errors, and summarize what you changed"
# machine-readable events instead:
codex exec --json "summarize the repo structure" | jq

Claude Code

Locked-down CI run
claude --bare -p "Run the tests and fix any failures" \
  --permission-mode dontAsk \
  --allowedTools "Read,Edit,Bash(npm test *)" \
  --output-format json > result.json

--bare skips auto-discovery of hooks, skills, plugins, MCP servers, auto memory and CLAUDE.md, so every machine gets the same run. It doesn't use your subscription login: set ANTHROPIC_API_KEY. Anthropic calls it the recommended mode for scripted calls.

OpenCode

opencode.json for CI
{
  "$schema": "https://opencode.ai/config.json",
  "permission": { "*": "deny", "read": "allow", "grep": "allow", "glob": "allow", "edit": "allow", "bash": { "*": "deny", "npm test*": "allow" } }
}
Run it
opencode run --format json -m <provider>/<model> "Run npm test and fix failures"

Explicit deny rules stay enforced even with --auto, which only auto-approves requests that would otherwise ask. To avoid MCP cold starts on every run, start opencode serve once and use opencode run --attach http://localhost:4096. OpenCode also has opencode github run for GitHub Actions.

goose

A recipe with parameters, no saved session
goose run --recipe weekly-report.yaml \
  --params week=2026-W42 \
  --no-session --max-turns 10

Recipes can declare a response JSON schema so the final output is structured. See the literature review recipe for a full recipe file.

Gemini CLI and Aider

One-shot runs
gemini -p "Summarize open TODOs in src/" --output-format json
aider --message "add descriptive docstrings to all the functions" src/utils.py

Example: nightly GitHub Actions job (Codex)

.github/workflows/nightly-agent.yml
name: nightly-agent
on:
  schedule: [{ cron: "0 9 * * 1-5" }]
jobs:
  run:
    runs-on: ubuntu-latest
    permissions: { contents: read }
    steps:
      - uses: actions/checkout@v4
      - run: npm install -g @openai/codex
      - run: codex exec -o report.md "Read the repo and list the 5 riskiest TODOs with file and line"
        env: { CODEX_API_KEY: "${{ secrets.CODEX_API_KEY }}" }
      - uses: actions/upload-artifact@v4
        with: { name: report, path: report.md }

This job is read-only by design: Codex's default sandbox is read-only and the workflow token can only read. Grant write access only for jobs that open pull requests.

FAQ

How do I run Codex non-interactively?

Use codex exec "task". It's read-only by default; add --sandbox workspace-write to allow edits, --json for JSONL events, or -o file to save the final message. --full-auto is no longer supported.

How do I run Claude Code in CI?

Use claude --bare -p "task" with --allowedTools for what it may do, --permission-mode dontAsk to deny everything else, and --output-format json. Bare mode needs ANTHROPIC_API_KEY.

Which harness is safest unattended?

The one whose defaults you've locked down. Codex starts read-only; Claude Code's dontAsk mode denies anything not pre-approved; OpenCode starts permissive, so set explicit deny rules.

Sources

  1. Codex docs: non-interactive mode · checked Oct 18, 2026
  2. Claude Code docs: run Claude Code programmatically · checked Oct 18, 2026
  3. Claude Code docs: MCP · checked Oct 18, 2026
  4. OpenCode 1 docs: CLI · checked Oct 18, 2026
  5. OpenCode 1 docs: permissions · checked Oct 18, 2026
  6. goose docs: CLI commands · checked Oct 18, 2026
  7. goose docs: recipe reference · checked Oct 18, 2026
  8. Gemini CLI docs: headless mode · checked Oct 18, 2026
  9. Aider docs: scripting · checked Oct 18, 2026

Spotted something out of date? Email sternberg@mail.grokbot.com.

Related