Claude Code Permission Modes Are Fleet Policy
Choose Claude Code permission modes by repository trust, define who can escalate them, and audit the same policy across an AI-agent fleet.
Go deeper. Build your own.
Clone an unfamiliar repository and muscle memory takes over: change directory, type claude, start asking questions. The dangerous assumption happens before the first prompt. You have treated the repository as trusted even though its hooks, scripts, dependencies, and instruction files have not earned that trust.
Claude Code does not currently document a --restricted flag. It documents --permission-mode, with modes such as default, acceptEdits, plan, dontAsk, and bypassPermissions. That correction matters because security guidance built around a nonexistent switch is worse than no guidance: it produces confidence without enforcement.
The durable lesson survives the flag correction. A coding harness can read files, edit a tree, execute commands, call network tools, and inherit instructions. Its permission mode belongs in the same policy as repository trust, branch protection, and approval ownership. It is not a cosmetic chat preference.
This playbook turns the current Claude Code controls into a repo-class policy, then shows where those controls stop. If you run several assistants through one operating view, each vendor still has its own permission vocabulary. The policy has to be shared even when the switches are not.
Use the framework as a decision record, not a universal preset. Revisit the mapping whenever a repository’s trust, a harness’s documented modes, or its surrounding sandbox changes. Record the mode selected, the evidence reviewed, and who approved any wider lane so later audits can distinguish policy from an operator’s assumption.
Know what each permission mode promises
Claude Code’s current permissions documentation separates several useful operating postures:
defaultasks for permission the first time a tool crosses a configured boundary.acceptEditsautomatically accepts file edits while other permission checks still apply.planlimits the session to analysis and codebase exploration with read-only tools until the operator approves a move into an execution mode.dontAskautomatically denies permission requests that are not already allowed by policy.bypassPermissionsremoves permission prompts and should be confined to isolated environments designed for that level of access.
Those are client-side permission behaviors, not interchangeable security boundaries. Plan mode is valuable for reconnaissance, but it does not turn an untrusted checkout into harmless text. A repository can contain deceptive instructions; a supposedly read-only command can reveal sensitive material; and a flaw in any tool can cross the boundary its interface intended. Anthropic documents sandboxing separately for exactly this reason.
Use three layers together:
- Permission mode controls what Claude Code may attempt without another decision.
- Allow and deny rules remove tools or command patterns that do not belong in that lane.
- Operating-system isolation limits the damage if the client policy, a tool, or your own judgment fails.
For source you merely want to inspect, plan is the narrow starting point. For actively hostile material, use a disposable VM or container with no credentials and no valuable mounts. Do not ask a CLI flag to perform the job of an isolation boundary.
Make unfamiliar code enter the narrow lane automatically
The best policy decision is the one you do not have to remember at 8:03 on a Monday morning. On Windows, a small launcher can clone evaluation repositories into a dedicated directory and open Claude Code in plan mode:
param(
[Parameter(Mandatory = $true)]
[string]$RepoUrl
)
$ErrorActionPreference = 'Stop'
$repoLeaf = ($RepoUrl.TrimEnd('/') -split '/')[-1]
$repoName = [IO.Path]::GetFileNameWithoutExtension($repoLeaf)
if ([string]::IsNullOrWhiteSpace($repoName) -or $repoName -in '.', '..') {
throw "Cannot derive a safe destination name from '$RepoUrl'."
}
$evalRoot = Join-Path $env:USERPROFILE 'eval'
$repoPath = Join-Path $evalRoot $repoName
New-Item -ItemType Directory -Force -Path $evalRoot | Out-Null
if (Test-Path -LiteralPath $repoPath) {
throw "Destination already exists: $repoPath. Review or remove it explicitly; this launcher will not reuse a checkout."
}
$cloneVerified = $false
try {
& git clone -- $RepoUrl $repoPath
$cloneExit = $LASTEXITCODE
if ($cloneExit -ne 0) {
throw "git clone failed with exit code $cloneExit."
}
$topLevelOutput = & git -C $repoPath rev-parse --show-toplevel
$topLevelExit = $LASTEXITCODE
$topLevel = ([string]$topLevelOutput).Trim()
if ($topLevelExit -ne 0 -or
[string]::IsNullOrWhiteSpace($topLevel) -or
[IO.Path]::GetFullPath($topLevel) -ne [IO.Path]::GetFullPath($repoPath)) {
throw 'Fresh clone verification failed: the destination is not the expected repository root.'
}
$originOutput = & git -C $repoPath remote get-url origin
$originExit = $LASTEXITCODE
$originUrl = ([string]$originOutput).Trim()
if ($originExit -ne 0 -or $originUrl -ne $RepoUrl) {
throw 'Fresh clone verification failed: origin does not match the requested repository.'
}
$cloneVerified = $true
Push-Location -LiteralPath $repoPath
try {
& claude --permission-mode plan
$claudeExit = $LASTEXITCODE
if ($claudeExit -ne 0) {
throw "Claude Code exited with code $claudeExit."
}
}
finally {
Pop-Location
}
}
catch {
if (-not $cloneVerified -and (Test-Path -LiteralPath $repoPath)) {
Remove-Item -LiteralPath $repoPath -Recurse -Force
}
throw
}
The script does not make the repository safe. It makes the first posture predictable. Before escalating the session:
- inspect
CLAUDE.md,AGENTS.md, hooks, package scripts, and bootstrap commands; - check for nested instruction files that apply only inside part of the tree;
- review what the proposed task actually needs to write or execute;
- remove credentials and broad mounts from the evaluation environment; and
- reclassify the repository only after a named human accepts the risk.
Claude Code also supports --bare, which skips hooks, plugins, MCP servers, auto-memory, and instruction loading for a minimal session. Bare mode still exposes core tools such as file operations and Bash, so it complements a narrow permission mode; it does not replace one. The CLI reference is the source to check before you encode either flag in automation.
Instruction files belong in the threat model
Repository trust is not just executable code. A harness reads standing instructions because they are supposed to shape its behavior. That makes an instruction file privileged input even when it cannot execute on its own.
Treat imported plugins, skills, gists, and instruction files like dependencies:
- Read the diff before adoption. Understand the tools, paths, and network behavior the instructions request.
- Pin a reviewed version. A mutable gist or moving branch should not become a silent standing order.
- Keep scope narrow. Project-specific guidance belongs in the project, not in a global file loaded everywhere.
- Give each rule an owner. Unowned guidance persists long after its original context disappears.
- Re-audit against real sessions. A rule that sounds concise may create repeated confusion or unnecessary context cost in practice.
Backpass is a useful example of the last step. It reads local transcripts from several coding harnesses, identifies evidence-backed instruction problems, and proposes budgeted edits for human approval. It does not prove that every imported AGENTS.md is malicious. It demonstrates a sound maintenance loop: compare durable instructions with actual session evidence instead of letting them accumulate by folklore.
The fleet policy table
A useful policy answers three questions: what kind of repository is this, which posture is the default, and who may widen it?
| Repository class | Default posture | Escalation owner |
|---|---|---|
| Personal repo with reviewed local rules | default; explicit allow and deny rules |
Repository owner |
| Team repo with CI and code ownership | default; managed settings where available |
Task operator plus code owner at review |
| Fork or dependency under evaluation | plan; no install or build commands yet |
Reviewer who has inspected instructions and scripts |
| Unknown download or prompt-injection sample | Disposable environment, plan or dontAsk, credentials absent |
Security owner; rebuild rather than relax in place |
| Imported plugin, skill, gist, or instruction pack | Do not enable until diffed and pinned | Person recorded as its maintainer |
| CI worker in a purpose-built ephemeral sandbox | Least permissions required for the job | Platform owner through managed policy |
The approver column prevents a familiar failure: a session starts narrow, becomes inconvenient, and gets widened because the current operator is impatient. Escalation should be a classification decision with a reason, not a mood at minute forty.
For teams, put the stable parts into managed settings rather than relying on every developer’s local file. Anthropic documents enterprise-managed settings and permission rule precedence; use them to prevent a project checkout from weakening an organization-level deny rule. Keep the table human-readable anyway. A JSON policy nobody can explain is difficult to review and easier to bypass accidentally.
Translate the policy, not the flag
The moment a second harness enters the fleet, --permission-mode plan stops being the policy. It becomes one implementation of the policy.
Codex, Gemini, Kimi, and other CLIs expose different combinations of approval modes, sandboxes, allowlists, and configuration files. Some controls are launch flags; others live in project or user settings. Trying to memorize an equivalent switch for every tool produces drift.
Keep a vendor-neutral vocabulary above them:
- Observe: inspect the repository; no writes, installs, or network side effects.
- Work: edit inside the repository and run an approved local test set.
- Elevate: use credentials, network access, deployment tools, or destructive commands only after a fresh approval.
- Isolate: run unknown or hostile material without valuable credentials, mounts, or persistent host access.
Then maintain a small translation for each installed harness. Test that translation after upgrades. If a mode disappears, changes semantics, or stops honoring a deny rule, the policy should fail closed and send the session back to Observe.
Test the policy like a control, not a preference
A permissions table that has never been exercised is documentation, not a control. Give every harness translation a harmless canary repository and verify the behavior that matters after installation and upgrades.
The canary should contain no real secrets. It should offer tempting but safe boundary tests:
- a writable file inside the repo and another outside it;
- a command that only reads local state;
- a command that would create a network request;
- a fake credential name in a fixture;
- a nested instruction file requesting an out-of-scope action; and
- an operation that should require a named human approval.
For Claude Code’s Observe lane, confirm that plan mode can inspect the repository but cannot make the proposed edit. Confirm that deny rules still block the tools or command patterns your organization forbids. For the Work lane, verify that expected repository edits and targeted tests succeed without granting access to unrelated paths. For Elevate, verify the approval prompt names the consequential action clearly enough for a human to decide.
Record four facts with the test result: harness version, policy revision, operating environment, and observed outcome. That makes a later regression diagnosable. “It used to ask” is not enough when command parsing, sandbox behavior, managed policy, or a local settings file may have changed.
Also test precedence. Claude Code settings can come from managed, command-line, local project, shared project, and user layers. A high-priority organization deny rule should not disappear because a cloned repository contains a permissive project setting. The current permissions docs define the precedence model; the canary proves your installed build and packaging apply it as expected.
Two failure responses should be automatic:
- If a narrow lane performs a prohibited action, stop using that translation and move the harness into an isolated environment until the cause is understood.
- If a legitimate action is blocked, change the policy deliberately or reclassify the task. Do not teach operators to bypass the prompt as a routine workaround.
This is the small discipline that keeps “least privilege” from becoming ceremony. The table defines intent; the canary supplies current evidence.
Audit the fleet without overstating enforcement
An inventory and transcript archive help answer two questions the flags cannot: which sessions were running, and what did they actually do? Automater Lite detects installed assistants and keeps its searchable Library local by default. Automater Pro adds advanced messaging and control, built-in terminal/repository/file browsing, and remote trust tiers described on the current product page. Those capabilities can make inconsistent launches visible and preserve evidence for review.
They do not magically set every vendor’s permission mode or turn a transcript into proof that an action was safe. Enforcement remains in vendor settings, operating-system isolation, and your approval process. The archive is the audit layer: search the relevant session, read its tool calls, correlate them with the diff, and confirm whether the intended lane held.
Automater Lite is free on automater.ai; Pro is $29/year.
That is the practical standard for fleet policy: one human rule, explicit vendor translations, real isolation where risk demands it, and enough local evidence to detect drift.
FAQ
Is there a claude --restricted mode?
Not in the current Claude Code CLI reference. Use claude --permission-mode plan for a read-only planning posture, or dontAsk when anything not explicitly allowed should be denied. Check the current reference when scripting flags because the surface can change.
Should plan mode be the default for cloned repositories?
It is a strong default for initial inspection because it limits the session to analysis and read-only exploration. Pair it with deny rules and an isolated environment when the repository is unknown or potentially hostile. Plan mode alone is not a sandbox.
How do I enforce one permissions policy across several AI CLIs?
Write the policy in vendor-neutral lanes such as Observe, Work, Elevate, and Isolate. Map each harness’s current modes and sandbox controls onto those lanes, make widening require a named approver, and audit sessions across vendors for drift.
Sources
- Claude Code permissions — current permission modes, rule evaluation, sandboxing, and managed settings
- Claude Code CLI reference — current
--permission-mode,--bare, and tool-control flags - Backpass — transcript-grounded instruction maintenance with human-approved writes
- Automater — current Lite and Pro product capabilities and pricing
