
Lock Down Claude Code for CI: allowedTools, permissionMode, and managed-settings.json
Chris Harper
2 min read
Jul 7, 2026 · 12:06 UTC
TL;DR: Pair allowedTools with permissionMode: "dontAsk" in .claude/settings.json to give unattended Claude Code runs only the permissions they need — nothing more, no prompts.
When Claude Code runs in an unattended pipeline — a GitHub Action, a scheduled routine, a deploy hook — the default permission model (prompt on anything unexpected) breaks automation. Here's how to build a minimal-permission profile where Claude can only do what the task actually requires.
The four settings layers
managed-settings.json ← enterprise-wide, cannot be overridden
└─ .claude/settings.json ← shared project (checked in)
└─ .claude/settings.local.json ← per-developer overrides (gitignored)
└─ CLI flags (--allowedTools, --permission-mode)
A deny at any level is final — lower levels can't override it.
Minimal CI profile
Add this to .claude/settings.json for a build/review agent that can stage and commit but cannot push or reach external services:
{
"permissionMode": "dontAsk",
"allowedTools": [
"Read", "Glob", "Grep", "Edit", "Write",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git add:*)",
"Bash(git commit:*)"
],
"denyTools": [
"Bash(git push:*)",
"mcp__*"
]
}
permissionMode: "dontAsk" means any tool not in allowedTools fails immediately rather than prompting. Combine with denyTools for an explicit blocklist that overrides any allow rule: even if an MCP tool appears in allowedTools, the mcp__* deny wins.
Narrowing further with CLI flags
For a read-only audit agent — no writes, no shell commands:
claude --permission-mode dontAsk \
--allowedTools "Read,Glob,Grep" \
--output-format json \
-p "List every file that hardcodes an API key"
Swap different --allowedTools sets to build task-specific profiles: one for code review, one for generating docs, one for running tests.
Enterprise enforcement via managed-settings.json
Admins can distribute a managed-settings.json that no project or user config can override:
{
"policySettings": {
"disableBypassPermissionsMode": "disable"
},
"denyTools": [
"Bash(rm -rf:*)",
"Bash(curl:*)",
"Bash(wget:*)"
]
}
disableBypassPermissionsMode: "disable" blocks the --dangerously-skip-permissions flag for all users in the org. The denyTools here are global: no project, no user, no flag can undo them.
Sources: Claude Code permissions docs, Claude Agent SDK permissions