CI/CD, GitHub Actions & Background Agents
Claude Code in the pipeline and on the cloud
- Authenticate Claude Code in CI using CLAUDE_CODE_OAUTH_TOKEN from claude setup-token
- Bound a headless run with --permission-mode dontAsk, --max-turns, and --max-budget-usd
- Dispatch, monitor, and clean up background agents and the daemon supervisor that hosts them
- Wire up PR autofix and scheduled cron routines that run on Anthropic's cloud
- Move a live session between claude.ai and your terminal with remote control and teleport
Run Claude Code without a human at the keyboard: authenticate in CI with a long-lived token, bound every headless run, dispatch and supervise background agents, schedule cron routines on Anthropic's cloud, and move sessions between the web and your terminal.
- 1The mental model: where the agent runs and who watches it
- 2CI authentication: a token, not a browser
- 3Bounding a headless run: three guardrails
- 4Background agents and the daemon supervisor
- 5PR workflows: autofix and resuming from a PR
- 6Scheduled routines on Anthropic's cloud
- 7Remote control and teleport: moving between web and terminal
The mental model: where the agent runs and who watches it
Interactive Claude Code assumes a human is present to approve edits and steer. Automation removes that human, so every unattended run needs two things the interactive session gave you for free: non-interactive auth (no browser login) and explicit bounds (so a runaway loop can't burn your CI minutes or your budget).
There are three places an unattended agent can live, and they differ in who supervises it:
| Where it runs | Started by | Supervised by | Use it for |
|---|---|---|---|
| CI / headless | claude -p in a GitHub Actions step or script | The CI runner itself (process exits, job ends) | One-shot checks, fixes, code review gated by exit code |
| Background agent | claude --bg / Ctrl+B / /background | The local daemon supervisor on your machine | Long tasks you dispatch and check on later |
| Anthropic cloud | --remote, /schedule, /autofix-pr | Anthropic's hosted runners (claude.ai) | Cron routines, PR watching, web sessions you teleport in |
The rest of this lesson walks each of these. The throughline: bounded, observable runs. You always know how to stop it, how much it can spend, and where to read its output.
Watch out
Claude Code needs a paid plan
Automation still consumes a real subscription or API quota. Claude Code is not on the free tier — you need Pro, Max, Team Premium, Enterprise, or a Console API key. From June 15, 2026, claude -p and Agent SDK usage on subscriptions draw from a separate monthly Agent SDK credit pool, distinct from your interactive limits.
CI authentication: a token, not a browser
Interactive login opens a browser. A CI runner has no browser, so you pre-mint a long-lived OAuth token and hand it to the runner as a secret.
Generate it once, on a machine where you're logged in:
claude setup-tokenThis prints a one-year OAuth token scoped to inference. It is printed, never saved to disk — copy it immediately and store it in your CI provider's secret store (e.g. a GitHub Actions repository secret). It requires an active Claude subscription, and it does not work in --bare mode.
In the runner, expose it as the environment variable Claude Code reads in CI:
# .github/workflows/claude.yml
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Claude Code
run: curl -fsSL https://claude.ai/install.sh | bash
- name: Run agent
env:
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
run: |
claude -p "Summarize what changed in this PR and flag risky diffs" \
--permission-mode dontAsk --max-turns 6 --max-budget-usd 2.00Why CLAUDE_CODE_OAUTH_TOKEN and not ANTHROPIC_API_KEY? Both work, but the OAuth token bills against your subscription, while an API key bills your Console account pay-as-you-go. Pick the one that matches how you want to pay. In the auth precedence order, CLAUDE_CODE_OAUTH_TOKEN sits just above interactive subscription OAuth, so setting it is enough — no /login needed.
Tip
Verify auth without a session
claude auth status prints your auth state (add --text for human-readable). It exits 0 when logged in and 1 when not, so you can gate a CI step on it before spending tokens.
Watch out
Never hardcode the token
Do not write the token into a workflow file, a committed .env, or a shell profile — a profile leaks it to every child process. Always inject it from the secret store at step scope, as in the env: block above.
Bounding a headless run: three guardrails
A headless agent with no human will keep working until it decides it's done — or until it loops. Three flags (all print-mode only, i.e. they require -p) put hard walls around it:
| Flag | What it caps | Behavior at the limit |
|---|---|---|
--permission-mode dontAsk | Permissions — auto-denies anything not in your allow rules | Any action that would normally ask becomes a deny; the agent can't escalate scope |
--max-turns 3 | Agentic turns | Exits with an error when the limit is reached |
--max-budget-usd 5.00 | Dollars spent on API calls | Stops cleanly when spend hits the amount |
Use them together. dontAsk is the key choice for CI: unlike bypassPermissions (which skips all checks and is only safe in a throwaway container), dontAsk is restrictive — it only permits what you've explicitly allowed and denies everything else, including actions that would otherwise prompt.
Pair dontAsk with an allowlist so the agent can actually do its job:
claude -p "Fix the failing unit tests, then commit" \
--permission-mode dontAsk \
--allowedTools "Read" "Edit" "Bash(npm test *)" "Bash(git commit *)" \
--max-turns 12 --max-budget-usd 3.00 \
--output-format jsonAdd --output-format json (or stream-json) when a downstream step needs to parse the result, and --json-schema '{...}' when you want the output validated against a schema.
Key insight
dontAsk vs bypassPermissions
They sound similar but are opposites. dontAsk = deny by default, allow only your rules — safe for CI. bypassPermissions (= --dangerously-skip-permissions) = skip all checks — only for isolated containers/VMs with no network. Reach for dontAsk plus --allowedTools in pipelines.
Tip
Gate the pipeline on exit code
claude -p and claude ultrareview return exit 0/1, so a review or test-fix step naturally fails the job when something's wrong. --max-turns exiting with an error is a feature here: a stuck agent fails loudly instead of silently spending.
Background agents and the daemon supervisor
Background agents are for long tasks you want to fire and check on later from your own machine — not block your terminal waiting. Start one three ways:
claude --bg "<task>"— start from the shell, print the session ID, return immediately- Ctrl+B — background the current interactive session (or the running bash command)
/background(alias/bg) — detach the current session as a background agent
Once running, you manage the fleet from the shell:
| Command | What it does |
|---|---|
claude agents | Open agent view to monitor/dispatch parallel sessions (--json to script, --cwd to filter) |
claude logs <id> | Print recent output from a session |
claude attach <id> | Attach to a running session in this terminal |
claude stop <id> | Stop a session (also claude kill) |
claude respawn <id> | Restart a stopped or running session, conversation intact (--all to restart every running one) |
claude rm <id> | Remove from the list — the transcript stays and is resumable via claude --resume |
All of these are hosted by a single local process: the daemon supervisor. It must be running for background sessions to exist. Two commands keep you out of trouble:
claude daemon status # supervisor state, version, socket dir, worker count; exits 1 if down
claude daemon stop --any # stop the supervisor and the sessions it hosts
claude daemon stop --any --keep-workers # stop supervisor but leave agents runningrespawn --all is the trick for picking up an updated Claude Code binary — it restarts every running agent on the new version without losing their conversations.
Note
Background tasks run shell commands too
claude --bg --exec 'pytest -x' runs a shell command as a PTY-backed background job instead of a Claude session — handy for kicking off a long build or test run you'll check with claude logs <id>.
Watch out
"Background service did not respond"
If agent view or claude agents reports an unresponsive supervisor, recover with claude daemon stop --any (add --keep-workers to preserve in-flight sessions), then re-open agent view to spin up a fresh supervisor.
PR workflows: autofix and resuming from a PR
/autofix-pr turns Claude into a CI watchdog for a branch's pull request. It watches the PR, and when CI fails or a reviewer leaves comments, it pushes fixes to the branch automatically — closing the iterate-on-feedback loop without you babysitting it.
/autofix-pr make sure all checks stay green and address review commentsIt has two hard requirements: the gh CLI must be installed and authenticated (so Claude can read PR/CI state and push), and you need Claude on the web (claude.ai), because the watching runs on Anthropic's cloud rather than tying up your terminal.
The complementary command runs locally. When Claude creates a PR, it links the session to that PR automatically. Later, from any machine, resume that linked work:
claude --from-pr 123
# or a full URL — GitHub, GitHub Enterprise, GitLab MR, or Bitbucket PR
claude --from-pr https://github.com/acme/app/pull/123This pulls up the session(s) tied to that PR so you can keep working with full context, instead of re-explaining the change.
Tip
The autofix loop
/autofix-pr is the cloud-side mirror of the local Explore-Plan-Implement-Commit loop: push → CI runs → fail/review → Claude fixes → push again, until checks are green. Scope it with a clear prompt so it fixes your failures and doesn't wander.
Note
Sessions link automatically
You don't tag a session to a PR manually. When Claude opens the pull request, the link is recorded for you — --from-pr just looks it up by number or URL.
Scheduled routines on Anthropic's cloud
Some agents shouldn't wait for you to start them — a nightly dependency audit, a weekly changelog draft, a morning triage of new issues. /schedule and /routines create and manage cron agents that run on Anthropic's cloud, not your laptop. That means they fire on schedule even when your machine is asleep.
/schedule every weekday at 9am, summarize new issues opened overnight and post a triage list
/routines/schedule [description] creates a routine from a natural-language schedule + task; /routines lists and manages the ones you've created. Because they run in the cloud, they pair naturally with /autofix-pr and --remote: the work happens server-side, and you check results from any surface — terminal, web, or the desktop app.
Key insight
Cloud cron vs local loop
Don't confuse /schedule with /loop. /loop [interval] [prompt] repeats a prompt only while your session is open on your machine. /schedule registers a cloud routine that runs independently on Anthropic's infrastructure on a cron schedule — survives reboots and closed laptops.
Remote control and teleport: moving between web and terminal
The same engine runs in your terminal and at claude.ai. These flags let a single session cross that boundary, so you can start work on one surface and continue on another.
| Flag / command | What it does |
|---|---|
claude --remote "<task>" | Create a new web session on claude.ai with this task description |
claude --remote-control "<name>" (--rc) | Start an interactive local session that you can also drive from claude.ai or the Claude app |
claude remote-control [name] | Run a Remote Control server with no local interactive session |
claude --teleport / /teleport (/tp) | Pull a web session into your local terminal to keep going there |
The two directions to keep straight:
--remotepushes a task out to the cloud (starts fresh on the web).--teleportpulls an existing web session in to your terminal.--remote-controlkeeps the session local but mirrors control to the web — useful when you start at your desk and want to nudge it from your phone.
This is what makes the cloud features practical: a /schedule routine or --remote task runs server-side, and when you want to take the wheel, --teleport brings it down to your terminal with full context.
Example
Start on web, finish in terminal
Kick off claude --remote "Migrate the auth module to the new SDK" from your phone on the train. At your desk, run claude --teleport, pick the session, and continue locally with your editor, tests, and debugger attached.
Try it: Wire a bounded autofix into CI
Build a safe, unattended pipeline end to end.
- Mint auth. On a logged-in machine, run
claude setup-token. Add the printed token to your repo's secret store asCLAUDE_CODE_OAUTH_TOKEN. Do not paste it anywhere committed. - Add a workflow. Create
.github/workflows/claude.ymlwith a job that checks out the repo, installs Claude Code (curl -fsSL https://claude.ai/install.sh | bash), and runs a bounded headless command. Inject the token via anenv:block at step scope. - Bound it. Use
claude -p "<task>" --permission-mode dontAsk --allowedTools "Read" "Edit" "Bash(npm test *)" "Bash(git commit *)" --max-turns 10 --max-budget-usd 2.00 --output-format json. Confirm the job fails (non-zero exit) when the agent can't finish. - Verify the guardrails. Temporarily lower
--max-turnsto1and re-run; confirm it exits with an error rather than continuing. - Add a watchdog (optional, needs gh + Claude on web). From an interactive session on a PR branch, run
/autofix-pr keep checks green and address review comments, push a deliberately failing commit, and watch it push a fix. - Schedule it (optional). Run
/schedule every weekday at 9am, run the test suite and open an issue if anything is red, then/routinesto confirm it registered.
Deliverable: a committed workflow file (token referenced only via secret), plus notes on which flag stopped the run in step 4 and why.
Key takeaways
- 1CI needs non-interactive auth: mint a one-year token with `claude setup-token`, store it as a secret, and expose it as `CLAUDE_CODE_OAUTH_TOKEN` (subscription billing) or use `ANTHROPIC_API_KEY` (Console billing).
- 2Bound every headless run with `--permission-mode dontAsk` (deny-by-default), `--max-turns`, and `--max-budget-usd` — all print-mode flags requiring `-p`.
- 3`dontAsk` is restrictive (allow only your rules); `bypassPermissions` skips all checks and is for throwaway containers only.
- 4Background agents (`claude --bg` / Ctrl+B / `/background`) are hosted by a local **daemon supervisor** that must be running; manage them with `claude agents/logs/attach/stop/respawn/rm` and `claude daemon status/stop --any`.
- 5`/autofix-pr` (needs `gh` CLI + Claude on web) watches a PR and pushes fixes on CI fail/review; `--from-pr` resumes the session linked to a PR; `/schedule` and `/routines` run cron agents on Anthropic's cloud.
- 6`--remote` pushes a task to the cloud, `--teleport` pulls a web session into your terminal, and `--remote-control` mirrors a local session to the web.
Quiz
Lock in what you learned
Check your understanding
0 / 4 answered
1.Your GitHub Actions job runs `claude -p` but fails with an authentication error. Which setup is correct for CI?
2.You want a headless agent in CI to only do what you've explicitly allowed and to deny everything else. Which flag fits, and how does it differ from the alternative?
3.Your `claude agents` view reports that the background service didn't respond, and your background sessions seem stuck. What's the right recovery?
4.You want Claude to keep a pull request green by fixing failures whenever CI breaks or a reviewer comments. Which mechanism does this, and what does it require?
Go deeper
Hand-picked sources to keep learning
Verbatim syntax for --bg, --from-pr, daemon, remote, teleport, and the bounding flags
setup-token, CLAUDE_CODE_OAUTH_TOKEN, and auth precedence order
/autofix-pr, /schedule, /routines, /background, /teleport
Managing background agents and the supervisor process
Official repo, issues, and release notes