Claude Code permission modes: which one should your CI use?
Most posts about Claude Code CI setup reach for --allowedTools, pile on a list of permissions, and call it done. It works. It also misses a whole axis of control: the permission mode sets the baseline behavior for a session, and the right mode shrinks your --allowedTools list to almost nothing. The wrong mode makes it a Swiss cheese of allowlists you forget to audit.
There are six modes. This is the field guide, ordered from strictest to loosest.
The six modes, at a glance
| Mode | Runs without asking | Best for |
|---|---|---|
| default | Reads only | Getting started, sensitive work |
| dontAsk | Only pre-approved tools via permissions.allow | Locked-down CI and scripts |
| plan | Reads only; proposes without editing | Exploring a codebase before changing it |
| acceptEdits | Reads, file edits, common filesystem cmds (mkdir, touch, rm, mv, cp, sed) | Iterating on code you're reviewing |
| auto | Everything, with background classifier safety checks | Long tasks, reducing prompt fatigue |
| bypassPermissions | Everything except protected paths | Isolated containers and VMs only |
Set a mode at startup with --permission-mode:
claude -p "..." --permission-mode dontAskOr pin it in settings.json:
{
"permissions": {
"defaultMode": "acceptEdits"
}
}The only one you should consider for unattended CI: dontAsk
From the docs, verbatim:
dontAskmode auto-denies every tool that is not explicitly allowed. Only actions matching yourpermissions.allowrules can execute; explicitaskrules are also denied rather than prompting. This makes the mode fully non-interactive for CI pipelines or restricted environments where you pre-define exactly what Claude may do.
That is exactly the property you want in CI. Every other mode is either interactive (default, plan) or loose (acceptEdits, auto, bypassPermissions). dontAskis the only one that combines “no human in the loop” with “no silent escalation.”
The tradeoff: you must have a permissions.allow list that actually covers what the job needs, or the run aborts on the first unapproved tool. Which is a feature. A dontAsk run that fails loudly is better than an acceptEdits run that quietly writes a file nobody expected.
claude --bare -p "Run the test suite and fix any failures" \
--permission-mode dontAsk \
--settings '{
"permissions": {
"allow": [
"Read",
"Edit",
"Grep",
"Bash(npm test)",
"Bash(git diff *)",
"Bash(git add *)"
]
}
}'Paired with --bare mode, dontAsk gives you the two properties that make a production Claude Code run safe to run unattended: reproducibility (bare) and bounded authority (dontAsk).
acceptEdits: looser, for interactive work
acceptEdits auto-approves file writes inside your working directory plus a specific list of filesystem commands: mkdir, touch, rm, rmdir, mv, cp, sed. Also the same commands wrapped in timeout, nice, nohup, or prefixed with safe env vars like LANG=C.
Everything else — arbitrary shell, network requests, writes outside your working directory — still prompts. That makes acceptEditsa decent choice for a human pairing with Claude in a long session where you'll review the diff at the end anyway. It is not a CI mode. If nothing is watching for the prompts, the run stalls.
plan: Claude as consultant, not contractor
Plan mode tells Claude to research and propose changes without making them. Reads files, runs shell commands to explore, writes a plan, does not edit your source. Permission prompts still apply the same as default mode, so humans still see the interactive permission requests.
Not a CI mode either, but a fantastic pattern for a pre-commit hook or a PR bot that comments on a diff: run Claude in plan mode with read-only tools, capture the plan as output, post it to the PR for a human to approve explicitly before a second non-plan run does the work.
auto: the research preview
Auto mode is the interesting one. Claude executes without permission prompts, but a separate classifier model reviews each action before it runs, blocking anything that escalates beyond your request, targets unrecognized infrastructure, or looks like it was driven by hostile content Claude read somewhere.
The classifier blocks a specific list of dangerous patterns by default: curl | bash, sending sensitive data to external endpoints, production deploys and migrations, mass deletion on cloud storage, granting IAM or repo permissions, modifying shared infrastructure, irreversibly destroying files that existed before the session, force push, and pushing directly to main.
Allowed by default:
- Local file operations in your working directory
- Installing dependencies declared in your lock files or manifests
- Reading
.envand sending credentials to their matching API - Read-only HTTP requests
- Pushing to the branch you started on or one Claude created
The catches:
- Plan requirement. Only on Team, Enterprise, or API. Not Pro, not Max.
- Model requirement. Sonnet 4.6 or Opus 4.6. Not Haiku, not claude-3.
- Provider requirement. Anthropic API only. Not Bedrock, Vertex, or Foundry.
- Admin requirement. On Team and Enterprise, an admin must enable it before users can turn it on.
- Aborts on repeated blocks. In headless
-pmode, 3 consecutive or 20 total classifier blocks abort the session — there's no user to prompt. Which means auto mode is fragile under adversarial or surprising content.
Auto is a serious research preview, and the classifier architecture is impressive, but the docs are clear it's not a replacement for review on sensitive operations. For a production background agent, dontAsk + a narrow allowlist is still the safer bet.
bypassPermissions: the footgun
bypassPermissions disables all permission prompts and safety checks. Only writes to protected paths (.git, .claude, shell rc files, etc.) still prompt. The docs are unambiguous:
Only use this mode in isolated environments like containers, VMs, or devcontainers without internet access, where Claude Code cannot damage your host system.
--dangerously-skip-permissions is the equivalent flag. The word dangerouslyin the name is not marketing. This is not a CI mode, unless your CI job runs in an ephemeral container with no network, no secrets, and no side effects you'd regret.
Protected paths, in every mode
Regardless of mode (except bypassPermissions, where they still prompt), writes to a fixed set of paths are never auto-approved. These guard your repo state and Claude's own configuration from accidental corruption.
Directories:
.git.vscode,.idea,.husky.claude— except.claude/commands,.claude/agents,.claude/skills, and.claude/worktrees, which Claude routinely creates content in
Files:
.gitconfig,.gitmodules.bashrc,.bash_profile,.zshrc,.zprofile,.profile.ripgreprc.mcp.json,.claude.json
In dontAsk these writes are denied outright, which means a background agent trying to modify any of them is telling you something important about its prompt.
The rule I use
For any unattended Claude Code run:
--barefor reproducibility (no hidden state)--permission-mode dontAskfor bounded authority- A narrow
permissions.allowlist (or an equivalent--allowedTools) --max-turnsand--max-budget-usdas the safety net behind the safety net--output-format stream-json+--verbose+--include-partial-messagesso you can watch the run from wherever you're watching it
Anything less strict is a choice worth justifying in a comment next to the cron entry.
Where this leaves you
You now know the permission axis. If you're running a single scheduled job on your own machine, that's all you need — pair these flags with cronand you're done.
If you're routing Claude Code runs from an issue tracker, you also need webhook signature verification, per-team budgets, mid-run approvals, audit trails, worktree isolation, and streamed output back to the issue. That's where background agents start, and most of the hard parts aren't about permissions — they're about all the plumbing nobody enjoys writing.
Cyrus ships the plumbing. You scope the permissions.
Cyrus runs Claude Code in isolated git worktrees per Linear issue, streams activity back, and supports mid-run approvals and dropdown interactions so “rich interactions” actually means “ask the human before doing the scary thing.” BYOK across Claude, Codex, Cursor, and Gemini. Community self-hosted is free forever.
Try Cyrus free →