Permissions

Permissions are the difference between a fast autonomous agent and a fast autonomous disaster. Everything else about Claude Code matters, but this one page decides whether your agent is safe to run without watching. Get it right and the agent handles 95% of your work without interrupting. Get it wrong and you either get buried in approval prompts or you wake up one morning to find something got deleted. Let's go through how to design it well.

The mental model.

Every time Claude wants to do something in the real world, use a tool, run a Bash command, call an MCP, Claude Code checks your permission rules first. The rules can say three things:

That's it. Three verdicts. The art is writing rules that sort actions into those three buckets correctly for your work.

~ how a tool call is evaluated ~

One thing to burn into memory: the deny list always wins. If a tool call matches both an allow pattern and a deny pattern, it's denied. This is what makes the system usable in practice: you can allow broad categories and deny narrow dangerous things inside them.

The four tiers of tool safety.

Before writing rules, it helps to classify actions into tiers by how much damage they can do. Every tool falls into one of these:

~ four safety tiers ~

Tier 1: Reads. Always safe. Allow widely.

Anything that just looks at data. Reading a file, listing a directory, grepping for a string, checking git status. These are information-gathering tools. They can't do harm. Allow them without thinking.

Example patterns for your allow list:

Tier 2: Local writes. Mostly safe. Allow with patterns.

Things that modify your own machine: editing files, running npm install, making local commits. These can go wrong (e.g., a bad edit), but the damage stays on your machine and is usually trivial to reverse with git.

Example patterns:

Tier 3: External writes. Risky. Ask every time.

Anything that affects the outside world. Pushing to a remote, creating a PR, sending an email, charging a credit card, posting to Slack. Once these go, you can't undo them quietly. Always ask.

Leave these OFF your allow list entirely. Claude Code's default behavior (ask) is the right answer:

Tier 4: Destructive. Deny always. No exceptions.

Things you never want the agent to do under any circumstances, not even with your explicit approval. Put these in the deny list so they don't even show up as prompts.

Canonical deny patterns:

The pattern syntax.

Rules use a compact pattern language:

Glob-style; no regex. Simple enough to reason about, expressive enough to cover what you need.

The canonical setup: broad allows + surgical denies.

The most maintainable pattern is to allow broad categories of action and then cut out the dangerous narrow cases. Example:

"allow": [
  "Read", "Glob", "Grep",
  "Edit", "Write",
  "Bash(git:*)",
  "Bash(npm:*)", "Bash(bun:*)",
  "mcp__notion__*",
  "mcp__github__read_*"
],
"deny": [
  "Bash(sudo:*)",
  "Bash(rm -rf:*)",
  "Bash(git push:*)",
  "Bash(git reset --hard:*)",
  "Bash(git push --force:*)",
  "mcp__github__delete_*"
]

Reading the list like a person: "You can do git stuff, npm stuff, read/edit files, and everything in Notion. But you can't sudo, can't rm -rf, can't push, can't force-push, can't hard-reset, and can't delete things on GitHub." That's usually exactly the right balance for a developer workflow.

Building your list: two passes.

Don't try to design the perfect list upfront. Build it the way a veteran sysadmin builds firewall rules: tight at first, then loosen where you're hitting friction.

~ the two-pass workflow ~

Claude Code ships a /fewer-permission-prompts skill that scans your session history and suggests patterns to add. It's the fastest way to tune a list from good to excellent.

Per-project overrides.

Drop a .claude/settings.json inside any project directory. Claude Code picks it up automatically when you run claude from that project. This lets you have:

You can also commit these configs into git so the whole team inherits the same guardrails.

The audit log.

Every tool call Claude Code runs goes into an audit log. Periodically, skim it. If you see something surprising, "oh, the agent ran mcp__stripe__list_charges, I didn't know it could do that", tighten the allow list. The audit log is how you find rules you should have denied and didn't.

The test for a good permission model: you stop noticing it. Not because you gave it everything, but because the friction lands exactly where real risk is. If you're constantly approving things, your allow list is too narrow. If you're ever surprised by something the agent did, your allow list is too broad. A well-tuned list is silent and safe.