Skip to content
Zarif Automates
Topics:Coding AI

Headless and CI Use of Coding Agents

ZarifZarif
|Published

An agent in CI has no one to answer its permission prompts. Every headless setup comes down to deciding those answers in advance: which tools run without asking, which are refused, and which secrets the process can see. Get that right and the rest is flags.

This page covers non-interactive mode in Claude Code and Codex, the GitHub integrations each vendor documents, how to handle keys, and a worked read-only review workflow for each tool. Everything is from the vendor docs as of September 26, 2026, starting with Claude Code's non-interactive mode page. The two worked workflows combine documented inputs and are labeled where they go beyond a verbatim example.

Claude Code without the prompt

Add -p to any claude command and it runs once, prints the result, and exits (non-interactive docs):

claude -p "What does the auth module do?"

It reads stdin, so it pipes like any Unix tool, and it exits non-zero on failure so scripts can branch on it. The flags that matter in automation:

FlagWhat it does
--allowedTools "Read,Edit,Bash(git diff *)"Pre-approves these tools. Permission-rule syntax; the trailing space-star allows prefixes
--permission-mode dontAskDenies anything that would prompt, except what allow rules cover. The docs call it useful for locked-down CI
--permission-mode acceptEditsWrites files without prompting; other shell commands still need an allow rule
--output-format jsonReturns the result, session ID, and cost estimate as JSON
--json-schema '...'Forces the result into your schema, in a structured_output field
--bareSkips hooks, skills, plugins, MCP servers, memory, and CLAUDE.md from the machine and repo
--resume "$session_id"Continues a specific earlier run

--bare deserves a closer look. Without it, the docs say a -p session runs the hooks in the repo's .claude/settings.json and connects the servers in its .mcp.json, with no trust dialog and no per-server approval, even in a folder you've never trusted. In CI that means the checked-out branch decides what runs. The docs recommend --bare for scripted calls and say it will become the default for -p in a future release. Bare mode also ignores your subscription login and needs ANTHROPIC_API_KEY.

One documented example shows the shape of a useful script check. It pipes a diff in, so Claude needs no Bash permission to read it:

git diff main | claude -p "you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else."

Codex without the TUI

codex exec is the Codex equivalent (Codex non-interactive docs). Progress goes to stderr and only the final message goes to stdout.

The default is the important part: codex exec runs in a read-only sandbox. You opt into writes with --sandbox workspace-write, or --sandbox danger-full-access for broader access, which the docs reserve for controlled environments. The older --full-auto flag is deprecated and prints a warning.

Other flags you'll use: --json for a JSON Lines event stream, -o or --output-last-message to write the final message to a file, --output-schema to enforce a JSON Schema, --ephemeral to skip saving session files, and codex exec resume --last to continue. For authentication in CI the docs show setting CODEX_API_KEY inline for the one command, and for GitHub Actions they point to the Codex action instead, which keeps the key behind a proxy.

Cursor's CLI follows the same pattern: agent -p for print mode, and changes are only proposed unless you add --force (Cursor headless docs).

The GitHub integrations

Claude Code GitHub Actions. The action is anthropics/claude-code-action@v1 (docs). The quick setup is /install-github-app inside Claude Code, which installs the Claude GitHub app, stores the secret, and opens a pull request with the workflow. It has two modes. With no prompt input, Claude waits for an @claude mention in an issue or pull request comment and replies there. With a prompt, it runs on whatever event triggers the workflow.

Two checks run before Claude starts: the triggering user needs write access to the repo, and bot actors are rejected unless listed in allowed_bots. On public repositories, GitHub withholds secrets from runs triggered by fork pull requests, so reviews run only on branches in the same repository.

The app's permissions are broad. Installing the official Claude GitHub app grants read and write on Actions, Checks, Contents, Discussions, Issues, Pull requests, Repository hooks, and Workflows, because one app serves several Claude features. GitHub doesn't let you accept a subset. The docs describe a custom GitHub app with just Contents, Issues, and Pull requests for organizations that need only the action.

Codex. Codex has two routes. Codex cloud runs tasks in cloud environments and returns diffs or pull requests; you can start one from the web, the IDE, the CLI, or by mentioning @codex on GitHub, and @codex review requests a code review (Codex cloud docs). By default, Codex blocks internet access during the agent phase, while setup scripts still run with internet so dependencies install (internet access docs). The other route is openai/codex-action@v1, which runs codex exec inside your own workflow (openai/codex-action).

Secrets and permissions

The docs from both vendors agree on the basics, and one detail from each is easy to miss.

  • Store keys as repository or organization secrets. Never commit them. Claude's action takes ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN (a subscription token from claude setup-token); for a secret shared across an organization, the docs recommend an API key, since an OAuth token is tied to one person's subscription.
  • Set the workflow's permissions block to the minimum. A review job needs contents: read. Only jobs that push need contents: write.
  • Claude: id-token: write is required for the action's default GitHub app authentication, per the docs' own examples.
  • Codex: the key is readable in the job. The codex-action README warns that the API key remains reachable through the proxy even in read-only mode, recommends against running on untrusted pull requests, and defaults to a drop-sudo safety strategy that removes the runner user's sudo access before Codex starts.
  • Cap the run. Claude's docs suggest --max-turns in claude_args, workflow timeouts, and GitHub's concurrency controls to avoid runaway cost. Runs on an API key bill at API rates plus your Actions minutes.

Worked workflow: a read-only rules check on pull requests

The target: on every pull request, the agent reads the diff against the base branch, checks it against the repo's instruction file, and writes findings to the job log. It can't edit, push, or comment. This is a composed example. The inputs and permission values come from the docs; the prompt and tool list are written for this page.

Claude Code version. Save as .github/workflows/agent-rules-check.yml:

name: Agent rules check
on:
  pull_request:
    types: [opened, synchronize, ready_for_review]

concurrency:
  group: agent-rules-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  check:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
      pull-requests: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            Compare this pull request's changes to origin/${{ github.base_ref }}
            with git diff. Check them against the rules in CLAUDE.md.
            List each rule the change breaks, with file and line.
            If it breaks none, say so in one line. Do not edit files.
          claude_args: |
            --max-turns 10
            --allowedTools "Read,Grep,Glob,Bash(git diff *),Bash(git log *)"

What each choice does:

  • fetch-depth: 0 gives the runner the base branch history so git diff has something to compare against. The docs' examples use a shallow fetch-depth: 1, which is enough for mention-driven work but not for a diff against the base.
  • The permissions block grants read only, plus the id-token: write the action needs to authenticate.
  • --allowedTools lists read tools and two git prefixes. The docs say that in automation mode Claude has no shell access until you grant the tools the prompt needs, so nothing else runs.
  • concurrency cancels a stale run when new commits land, and timeout-minutes caps a stuck one.

Findings appear in the workflow run log, which is the documented default for automation mode. To post a comment instead, the docs' code-review example shows the extra tool and flag it takes.

Codex version. The same check with the Codex action. The checkout and fetch steps follow the action's README example; :read-only is the permission profile the README names for read-only workflows:

name: Codex rules check
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  check:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v5
        with:
          ref: refs/pull/${{ github.event.pull_request.number }}/merge
          persist-credentials: false
      - name: Fetch base and head
        env:
          PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          git fetch --no-tags origin "$PR_BASE_REF" "+refs/pull/$PR_NUMBER/head"
      - uses: openai/codex-action@v1
        with:
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
          permission-profile: ":read-only"
          prompt: |
            Compare the changes between origin/${{ github.base_ref }} and HEAD.
            Check them against the rules in AGENTS.md. List each rule the
            change breaks, with file and line. Do not edit files.

The README notes that permission profiles are beta and need Codex CLI 0.138.0 or later, so don't pin an older codex-version with this input. The final message is available as the step's final-message output if you want a later job to post it.

What to automate first

Start read-only. A check that reports into the log costs little if it's wrong, and a week of its output tells you whether it's worth letting it comment, then push. The diff review guide in this series covers what to look for when it does start writing code. For deployment concerns beyond coding agents, deploying AI agents to production covers monitoring and rollback.

Previous in the series: Skills and reusable instructions for coding agents. Next: Codex vs Claude Code vs Cursor.

Zarif

Zarif

Zarif builds AI agents and automation workflows and writes about what holds up in production: useful sources, the roles the AI era is creating, and agent workflows you can inspect end to end.