Claude Code Security Patterns: The Permission Rules I Wish I'd Set Up Sooner

By default, Claude Code can read any file and run any command on your machine. That's the point — it's supposed to be capable. But it also means every single bash command triggers an approval prompt, and clicking "don't ask again" only covers that exact command. Ask for npm run test a different way tomorrow, and you're approving it all over again. Multiply that by a real workday, and it's genuinely annoying enough that people start approving things without reading them — which is worse than the popups.
The three permission levels#
- Reading files — instant, no question asked. Looking at code, listing files, searching.
- Running commands — needs your approval, because a bash command can do anything on your machine. Say yes once, tell Claude not to ask again, and it remembers that for the project — but only for that exact command.
- Changing files — always asks. And unlike commands, this one resets: close Claude Code, and next session it asks again.
Reading is instant. Commands can become permanent. File changes reset every session. That's the default. The fix for "why does it keep asking" isn't approving faster — it's writing rules.
Writing rules instead of clicking yes forever#
The quick way: type /permissions and describe the rule — the tool, then in brackets what you want. bash(npm run test:*) allows anything starting with npm run test. Claude writes that straight into your settings file.
The real power shows up when you edit settings.json directly. Everything lives under a permission object with three categories: allow (do it, no question), ask (always prompt), deny (block completely). Priority order matters here: deny beats allow, and allow beats ask. You can write what looks like a clean allow rule and have it silently overridden by a deny rule elsewhere — worth knowing before you spend time debugging why a command is still blocked.
The three tools that map to the three permission levels: read, bash, edit. You can move any of them between categories — put reading into deny if you want it fully blocked, or into ask if you want a prompt before Claude even looks at something.
Blocking secrets from being read, concretely#
Paths in these rules resolve relative to the folder containing settings.json. A real, common rule: block Claude from reading your .env file entirely.
{
"permission": {
"deny": ["read(./.env)"]
}
}Ask Claude what's in your .env after that, and you get permission denied — not a summarized answer, not a partial read. Blocked.
In the video#
- 00:04 — The three permission levels: read, bash, edit
- 01:10 — Why per-command approval breaks down, and how permission rules fix it
- 02:30 — The
settings.jsonstructure: allow / ask / deny, and the priority order - 03:48 — Blocking
.envreads, concretely - 05:06 — The settings hierarchy — four levels, and which one wins
The hierarchy nobody tells you about#
This is the part worth actually remembering: settings.json isn't the only place permissions can come from, and there's a strict order for which one wins — like a chain of command, most powerful first.
- Enterprise policies — set by your company's IT admin. Cannot be overridden, period. If the admin says no one deletes files, no one deletes files, no matter what any other setting claims.
- Local project settings — your personal overrides for one specific project. Typically gitignored, so it's just for you — extra protection you want, even if the team allows more.
- Shared project settings — the team configuration, committed to git. Everyone who clones the repo gets the same rules. Most of your project-wide security policy lives here.
- Personal global settings — your home-folder defaults, applied to any project that doesn't define its own rules.
The actual point#
The popups aren't the problem. Reacting to them one at a time is. Write the rules once — deny the things that should never be readable, allow the commands you run constantly, leave ask for the stuff that actually deserves a second look — and put them at the right level of the hierarchy so the whole team inherits the same boundary instead of everyone quietly clicking yes to different things.
AI engineering, weekly.
Join developers getting practical AI engineering in their inbox.