Permissions & Settings
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page is written against the Claude Code CLI 2.1.283, VS Code 1.139 with the GitHub Copilot Chat extension, and the GitHub Copilot CLI 1.0.88, all re-verified as current as of 2026-09-28; re-check the linked docs before relying on an exact key name, since both products change these surfaces often. Every rule, key and mode named below was checked against the live documentation on that date; where a detail could not be confirmed, this page describes the behavior without naming a key.
Claude Code enforces permissions itself, independently of what a prompt or CLAUDE.md asks for — instructions
shape what Claude tries to do, settings and modes decide what Claude Code actually lets it run. Keep that
distinction in mind throughout this page: a well-written skill or instruction file is not a substitute for a
deny rule, and Hooks covers the one mechanism (a blocking
PreToolUse hook) that sits above even a matching allow rule.
The settings hierarchy and precedence
Claude Code reads JSON settings from several files and merges them, with a fixed precedence when the same key is set in more than one place. Verified against Claude Code — Settings files and precedence, highest first:
| Level | File / source | Who it affects |
|---|---|---|
1. Managed |
|
Every developer the organization deploys it to; nothing else overrides it, apart from a short list of security-sensitive exceptions |
2. Command line |
|
The current session only |
3. Project local |
|
The current user, in this project only — Claude Code keeps it out of git when it creates the file; add it
to |
4. Shared project |
|
Everyone working in the project, once the file is committed |
5. User |
|
The current user, across every project on their machine |
List-valued keys such as permissions.allow merge across every file that sets them instead of the higher level
replacing the lower one outright; some keys never take effect from a repository file — for example permissions.defaultMode set to auto or
bypassPermissions applies only from user, --settings or managed settings, never from project or local
files — and a few security-sensitive keys honor a stricter value even over managed settings. See
the full precedence rules and their exceptions before relying on an
edge case.
.claude/settings.json{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(mvn test)",
"Bash(git status *)",
"Bash(git diff *)",
"Read(./docs/**)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./secrets/**)",
"Read(./.env)"
]
},
"env": {
"DOCS_ASSISTANT_ENV": "local"
}
}
Settings files are strict JSON — a // comment or a trailing comma is a syntax error that Claude Code reports
as a Settings Error at the next start, so keep an example like this one comment-free even when annotating it in
prose.
Allow, ask and deny rules
A permission rule is a bare tool name (matches every use of that tool) or Tool(specifier) (matches a narrower
pattern). Verified against Claude Code — Configure permissions:
| Rule | Matches |
|---|---|
|
Any |
|
As a |
|
One tool from one configured MCP server, e.g. |
|
Fetches to that exact hostname; |
Rules are evaluated in a fixed order — deny, then ask, then allow — and the first match wins regardless of
how specific a lower-priority rule is: a broad deny such as Bash(aws *) blocks a call even when a narrower
allow such as Bash(aws s3 ls) also matches it. A bare tool-name deny (just Bash, with no specifier)
removes the tool from Claude’s context entirely, so Claude never sees it as callable; a scoped rule such as
Bash(rm *) leaves the tool available and blocks only matching calls.
Permission modes
Getting Started with Claude Code introduces the modes most relevant when starting out (Manual, Accept edits, Plan, Auto). The full set, verified against Claude Code — Choose a permission mode:
Mode (defaultMode value) |
What runs without asking |
|---|---|
Manual ( |
Reads only; asks before file edits, shell commands and network access. |
Accept edits ( |
Reads, file edits and common filesystem commands for paths inside the working directory. |
Plan ( |
Reads and read-only exploration only; no edits until a plan is approved. |
Auto ( |
Almost everything, reviewed in the background by a separate classifier model instead of a prompt. |
|
Auto-denies anything that would otherwise prompt, apart from what an |
|
Skips permission prompts entirely, except for a short list of actions no mode auto-approves. This is a full
bypass, not a convenience mode — |
Pick the mode a session starts in with permissions.defaultMode in a settings file, or for one run with
--permission-mode:
.claude/settings.json{
"permissions": {
"defaultMode": "plan"
}
}
$ claude --permission-mode acceptEdits
Administrators can remove the two broadest modes altogether by setting permissions.disableBypassPermissionsMode
or permissions.disableAutoMode to "disable" in managed settings. See
Claude Code — Choose a permission mode.
Sandboxing
Permission rules and modes decide whether an action runs without asking; they are not an isolation boundary. Securing AI-Assisted Development covers sandboxing and network allowlists in depth; the essentials, verified against Claude Code — Sandboxing:
-
Once enabled (with
/sandboxorsandbox.enabledin a settings file), Claude Code’s Bash sandbox enforces filesystem and network isolation at the OS level (Seatbelt on macOS,bubblewrapon Linux and WSL2) on every Bash, PowerShell or Monitor command and its child processes. The sandbox is not a permission mode; it restricts what a command can reach once it runs, whichever mode approved it. -
No domain is pre-allowed by default. The first time a sandboxed command needs a new host, Claude Code prompts for it; hosts listed in
sandbox.network.allowedDomains, and any domain already covered by aWebFetch(domain:…)allow rule, skip that prompt. -
The Bash sandbox constrains shell commands only — built-in tools such as Read, Edit and WebFetch are still gated by ordinary permission rules, and MCP servers and hooks run unconstrained on the host unless the whole process runs inside a container, VM or the separate sandbox runtime package.
-
An organization can lock the allowlist with
sandbox.network.strictAllowlist(deny instead of prompt for any host outside it) orsandbox.network.allowManagedDomainsOnlyin managed settings (only the managed entries are honored at all).
managed-settings.json{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
failIfUnavailable stops Claude Code from starting when the sandbox can’t initialize, instead of falling back
to unsandboxed execution, and allowUnsandboxedCommands: false removes the escape hatch that lets Claude retry a
blocked command outside the sandbox. See
Claude Code — Sandboxing.
How skill allowed-tools interacts with settings
A SKILL.md file’s allowed-tools frontmatter pre-approves the
listed tools for the single turn that invokes the skill, so Claude can use them without an interactive prompt;
invoking the skill again re-applies the grant for that turn. It does not restrict which tools are otherwise
available — every tool still remains callable and ordinary settings still govern anything not listed (verified
against Claude Code — Skills). The grant goes through the normal
permission flow, where rules are evaluated deny, then ask, then allow, and an explicit ask rule is never
auto-approved in any mode (Claude Code — Configure permissions).
The interaction is therefore one-directional: deny and ask rules still override allowed-tools. A skill
cannot grant its way past an organization’s deny rule, and an ask rule still interrupts the skill’s own turn
even though allowed-tools named that tool:
.claude/skills/release-notes/SKILL.md (frontmatter)---
name: release-notes
description: Draft release notes from the commits since the last tag, then push the notes branch. Use whenever the user asks for release notes.
allowed-tools: Bash(git log *) Bash(git tag *) Bash(git push *)
---
.claude/settings.json{
"permissions": {
"ask": ["Bash(git push *)"]
}
}
With both files in place, git log and git tag run without a prompt while the skill’s turn lasts, but
git push still prompts, because the project’s ask rule wins over the skill’s grant. Workspace trust doesn’t
gate allowed-tools either — a project skill’s grant applies even in a -p run in a folder nobody trusted — so review the allowed-tools of skills checked into a repository before running Claude Code there. This is why iru-code’s `allowed-tools
(shown on the Skills page) lists narrow Bash(<prefix> *) entries
rather than a bare Bash — a scoped grant composes safely with a project’s own deny rules, a bare one would
just widen what needs denying elsewhere.
GitHub Copilot tool approvals
VS Code’s chat permissions picker offers three permission levels, and the separate Autopilot agent mode auto-approves tools too, verified against VS Code — Manage approvals and permissions:
| Level or mode | What it does and its risk |
|---|---|
Manual permissions (default) |
Uses the workspace’s tool, URL and terminal approval settings; anything not auto-approved still asks. The safest default. |
Assisted permissions (experimental) |
An LLM judge reviews each tool call; a call the judge does not approve still asks. Faster than Manual, but the judge is itself a model call and can misjudge a genuinely risky action — treat it as a convenience, not a security boundary. |
Allow all |
Runs every tool call without confirmation for the session. No per-tool or per-command scoping; a destructive edit or command runs exactly as readily as a safe one. |
Autopilot (an agent mode, not a permission level) |
Auto-approves every tool like Allow all, retries on errors, and answers blocking questions automatically
instead of pausing for the person. The broadest option — equivalent in spirit to Claude Code’s
|
Finer-grained, persistent auto-approval is set through chat.tools.* settings rather than the per-session
picker, also verified against the same page:
| Setting | What it controls |
|---|---|
|
Auto-approves tool calls across every workspace once enabled. VS Code shows a warning dialog the first time you enable it, because it removes confirmation prompts everywhere, not just in the current project — the closest Copilot equivalent to a broad Claude Code bypass, and carries the same risk: only enable it on a machine or account where every workspace is already trusted. |
|
Setting a tool to |
|
Auto-approves ( |
|
Auto-approves URL fetches by pattern — widen this deliberately, since an auto-approved fetch is exactly the surface prompt injection through repo content, issues and MCP tools targets. |
Organizations set org- and enterprise-level Copilot policies — which features, models and agents are available to a team, and whether an individual can override settings like these for themselves — from organization or enterprise settings, documented at GitHub Copilot policies for enterprises and organizations. The nearest Claude Code equivalent is managed settings, covered below.
Safe defaults for CI
Headless & CI Automation covers running each tool unattended end to end; this section states the permission-side rule that page’s examples follow: grant a CI job only the narrowest allowlist the prompt actually needs, and never reach for a broad bypass just because nobody is present to answer a prompt.
$ claude -p "Look at my staged changes and create an appropriate commit" \
--allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)" \
--permission-mode dontAsk
settings.json{
"chat.tools.terminal.autoApprove": {
"git diff": true,
"git status": true,
"git log": true,
"git push": false
}
}
The Copilot cloud agent has no approval prompts to tune: it runs in an ephemeral sandbox with every tool
pre-approved, so its safety levers are that sandbox’s firewall and preToolUse
hooks, not an allowlist (see
GitHub Copilot — Hooks reference).
Both examples name specific command prefixes rather than a bare Bash/terminal grant, and neither reaches for
--dangerously-skip-permissions, bypassPermissions, chat.tools.global.autoApprove or Autopilot — a broad
grant belongs only inside a disposable, network- and filesystem-restricted runner, never in a workflow that
reviews content from an untrusted fork, per
Safe permission
settings for CI. See Claude Code — Run Claude Code programmatically
for --allowedTools and dontAsk in -p runs.
For an organization running many such jobs, pin the allowlist itself in managed-settings.json rather than
trusting every repository’s own .claude/settings.json, so a compromised or careless project file cannot widen
what CI is allowed to run. allowManagedPermissionRulesOnly in managed settings additionally makes managed
settings the only source of permission rules — Claude Code then also drops allow rules passed as
--allowedTools, so the managed list itself must cover what the job runs:
managed-settings.json{
"allowManagedPermissionRulesOnly": true,
"permissions": {
"allow": ["Bash(git diff *)", "Bash(git log *)", "Bash(git status *)", "Bash(git commit *)"],
"deny": ["Read(./.env)", "Bash(git push *)"],
"disableBypassPermissionsMode": "disable"
}
}
See Claude Code — Deploy managed settings for the delivery mechanisms (a file, MDM, or the claude.ai console) and precedence details.
Related pages
-
Building CLIs for AI Agents (designing the command-line tools that these permission rules gate)