Skip to content

Headless & CI

You tried to wire the agent into a script and the TUI got in the way. It wants to confirm permissions. It wants to draw a status bar. It’s expecting a human to type. The thing that’s effortless interactively is suddenly a fight against the loop you didn’t realise was assumed.

What you were trying to automate is the part the agent is great at when you’re driving it: triaging an incoming bug report, drafting a release-notes summary from a diff, sweeping the codebase for missing test coverage, generating a TL;DR of a long PR description. You’d love this to just happen. On the schedule. On the GitHub event. As part of CI. Without you sitting there.

Headless mode is the entry point with the human assumption removed. The same agent, the same skills, the same model - but invoked as a subprocess that takes input from stdin or a flag, produces output to stdout (often as structured JSON), and exits with a status code.

Now your nightly job, your GitHub Action, your pre-push git hook, your Slack /triage slash-handler - all of them can call the agent like any other command-line tool.

Every CLI in scope has that non-interactive surface: you pass a prompt, the agent runs its loop to completion, prints a result, and exits. No TUI, no live editing, no approvals - just call it from a script, get an answer back.

The shapes converge - all of them give you a run / exec / -p / --prompt subcommand - but the surrounding ecosystem (SDKs, GitHub Actions, structured-output formats, remote execution, async background agents) differs significantly. That’s usually what tips the decision when you’re choosing one for an automation.

Two tools go further than a local headless command. Copilot’s canonical headless surfaces are Coding Agent (background, async, GitHub-native) and the copilot CLI - both non-IDE. Cursor ships three: cursor-agent headless, Cloud Agents (REST API), and Bugbot (PR reviewer).

Real-world examples of headless agent runs:

  • CI code review - on every PR, an Action runs the agent against the diff and posts findings as a PR comment. Catches the easy stuff before a human reviews.
  • Issue triage - incoming GitHub issue triggers a workflow that asks the agent to label it, link related issues, and ping the right code-owner.
  • Release notes - nightly, the agent reads the day’s merged PRs and drafts a CHANGELOG entry. Human edits before publishing.
  • Test-gap audits - scheduled job: “list every public function added this week that has no test.” Output goes to a Slack channel.
  • Doc freshness checks - weekly run that grep’s for TODO: verify markers and asks the agent to confirm each one against current code, opening issues for the stale ones.
  • Cron-style summaries - daily standup digest from git log, weekly velocity report, monthly tech-debt scan.
  • Embedded in tooling - a custom CLI in your repo (bin/team-tool review) that wraps the agent SDK for repeatable, parameterised flows.
  • Background PR work - assign a GitHub Issue to Copilot Coding Agent, walk away, come back to a draft PR.

The test: if you’re describing the task to the agent in approximately the same shape every time, and the result is something a script could consume, it belongs in headless mode.

Pick a task, an output format, and a permission posture, and the same CI job assembles into that tool’s command. Watch where the posture ends up: an allowlist flag, a sandbox tier, or a config file the command never mentions.

Task
Output
Posture
claude -p "Review the changes on this branch for regressions. Be terse." \
  --bare --allowedTools "Read,Bash(git diff *)" --permission-mode dontAsk \
  --output-format json
  • postureThe allowlist is the guardrail - tool patterns like Bash(git diff *) scope commands, not just tools. --bare skips auto-discovery of CLAUDE.md, hooks, and MCP servers so CI behaves deterministically, and dontAsk keeps the run from hanging on an approval no one will answer.
  • outputOne structured object with result, session_id, cost, and usage. Capture session_id if a later run should --resume this one.
  • beyondFirst-party CI: anthropics/claude-code-action@v1 wraps all of this in a GitHub Action - pass any of these flags via claude_args.
You want to…Reach forNot
Run the agent unattended from a script or CI jobHeadless / run / exec / --promptInteractive TUI
Build a long-running custom automation around the agentSDK (Claude Agent SDK / Codex SDK / OpenCode SDK)Shelling out every time
Run the agent on a remote machine / sandboxed envCodex Cloud, OpenCode + Docker, a hosted Claude Agent SDK application, Cursor Cloud AgentsLocal headless alone
Get structured JSON output for scripts to parse--output-format json / --json / --format jsonGrepping plaintext
Resume a previous session non-interactivelyclaude -c/--resume (Claude Code), codex resume (Codex), session APIs in SDKsRestarting from scratch
Run unattended and keep humans in the loop on risky actionsHeadless + tight permissions + hooksHeadless with full access
Embed the agent inside another productSDKWrapping the CLI binary
Trigger an agent from a GitHub Issue or @-mentionCopilot Coding AgentPolling for events from a local headless run

The TUI is for driving the agent. Headless mode is for the agent being driven by something else. SDKs are for the agent being part of a bigger program. Pick by how much orchestration you need around the call.

Command: claude -p "<prompt>" (or claude --print "<prompt>").

Runs the agent loop until it produces a final answer, prints stdout, exits. Suitable for shell pipelines.

CI integration: use the official Claude Code GitHub Action for the supported GitHub-native path. The Claude Agent SDK is a standalone embeddable package for applications that need programmatic control; if you use it in CI, your workflow still hosts and invokes that application.

Streaming output: --output-format json for structured output; --output-format stream-json for line-delimited streaming.

SDK packages:

  • npm: @anthropic-ai/claude-agent-sdk (renamed from @anthropic-ai/claude-code mid-2026)
  • PyPI: claude-agent-sdk
AspectClaude CodeCodexOpenCodeCursorCopilotPi
Headless commandclaude -pcodex execopencode runcursor-agent -pcopilot --promptpi -p
Structured output--output-format json--json / --experimental-json + optional --output-schema--format jsonjson, stream-json, --stream-partial-output---mode json
Streaming outputstream-jsonNDJSON (default with --json)line-delimited JSON via --format jsonstream-json / partial output-Via RPC mode
Session resume/fork-c/--continue, -r/--resume <id>, --fork-session (all headless)codex resume, codex forkSessions w/ undo-redo/resume (CLI)-Interactive /tree session picker; non-interactive resume is surface-dependent
Remote / async executionAgent SDKcodex cloud execDocker / self-hostedCloud Agents API (REST)Coding Agent (background, GitHub-native)-
First-party CI integrationClaude Code GitHub ActionGitHub ActionGitHub / GitLab integrationsBugbot (PR reviewer)GitHub Actions, Coding Agent, PR reviewpi -p scripted into any CI runner
Programmatic SDKClaude Agent SDKCodex SDKOpenCode SDKCloud Agents REST APIGitHub REST/CLI surfaces; task dispatch depends on the documented Copilot surfacePi SDK + RPC mode
  • “Headless” in Claude Code (claude -p) is the same idea as Codex’s exec, OpenCode’s run, Cursor’s cursor-agent -p, and Copilot CLI’s --prompt - but each tool’s SDK or background-agent surface is the more powerful path for non-trivial automation.
  • Codex Cloud is not the same as “remote MCP” - Cloud runs the whole CLI remotely; remote MCP just connects a local CLI to a remote tool server.
  • Copilot Coding Agent (background async PR work) is a different surface from Copilot CLI headless (copilot --prompt). The older gh copilot GitHub-CLI extension was retired in October 2025 - don’t confuse it with either of the two live surfaces.
  • Cursor Cloud Agents (REST API, GitHub-native) ≠ cursor-agent headless (local CLI) ≠ Bugbot (PR reviewer service).

Start smaller than a GitHub Action. Take one task you already run by hand, invoke it once with your tool’s headless flag and JSON output, and read what lands on stdout - that tells you whether the automation wants a shell script, a scheduled job, or the SDK. Tighten permissions before you put it on a trigger: an unattended run has nobody left to say no.