anfloy.AcademyBook a call

Foundation · 02 · How Claude Code thinksLesson 4 of 5

Permissions, approvals & guardrails

40 min working time · Week 2

By the end of this lesson you can
  • Configure what Claude may do with and without asking
  • Set safe defaults for non-technical teammates
  • Know the irreversibility rules before you need them

Three layers of control

When this lesson is done, your project has committed guardrails: deny rules you have watched Claude obey, an allowlist built from real usage, and the sandbox on. Hold the whole safety model in one line: CLAUDE.md shapes behavior but is advisory - Claude follows it the way a good employee follows a handbook. Permissions enforce - the tool itself blocks or allows actions, no judgment involved. The sandbox contains - the operating system limits what commands can even touch.

By default Claude Code asks before anything consequential: editing files, running commands that change things, fetching the web. Reading files in your project and other read-only operations run without prompts. Your job in this lesson is to tune the asking so it protects you without interrupting you forty times an hour.

Permission rules: allow, ask, deny

Rules live in settings files and name a tool, optionally with a specifier. Evaluation order is deny, then ask, then allow - first match wins, and a deny anywhere always wins. The easiest way to manage them is the /permissions screen inside a session; under the hood it edits the same settings.json you can also write by hand.

.claude/settings.json - a starter permissions block
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git diff *)",
      "Read(./reports/**)"
    ],
    "ask": [
      "WebFetch"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env*)",
      "Edit(./archive/**)"
    ]
  }
}
  • Bash(git diff *) - allow a command pattern. The space before * matters: it matches at word boundaries, so it cannot be tricked by a longer command name.
  • Read(./.env*) - deny reading secrets files. Do this in every project, today.
  • Edit(./archive/**) - path rules use gitignore-style globs. // means absolute path, ~/ home, / project root.
  • Rules can also target connected tools (mcp__server__tool), skills (Skill(name)), folder changes (Cd(~/work/**)), and tool parameters in deny and ask rules: Agent(model:opus) matches Agent calls that request the Opus alias.

Permission modes: the dial you switch with Shift+Tab

  • Manual (config value default) - asks per your rules. Older docs and tutorials call this mode 'default'; the label changed in July 2026, the value did not.
  • acceptEdits - file edits in the project auto-approve; commands still ask. Good for heavy editing sessions in low-stakes folders.
  • plan - Claude can only read and plan, never change anything. Next lesson lives here.
  • auto - a classifier reviews each action: routine ones proceed, risky ones are blocked (retry one with manual approval from /permissions), and repeated blocks drop the session back to prompting you. Since Claude Code v2.1.283 (September 2026) this is the built-in starting mode for interactive terminal and VS Code sessions on every plan. Headless runs and the Agent SDK still start in Manual.
  • dontAsk - deny by default: anything not explicitly allowed is refused rather than asked. Built for unattended runs.
  • bypassPermissions - everything auto-approves. For disposable environments only, and admins can lock it off entirely.

Press Shift+Tab in a session to cycle modes, or set defaultMode in your user settings. The honest guidance: auto or Manual for daily work, plan for anything you are unsure about, dontAsk for anything unattended, and treat bypassPermissions as a tool you do not need.

On irreversibility: permissions exist because some actions cannot be undone - deleted files, sent emails, an API call that charged a card. The rule to internalize before you need it: anything irreversible stays behind an ask. Our own version was written after a bare --send flag on an internal script put 14 unapproved replies into real prospects' inboxes: Claude produces drafts, and any send path needs a named target, an explicit flag and a typed confirmation. Claude Code also has its own circuit breakers - even in bypass mode it refuses catastrophic deletes at the root or home-directory level - but your deny rules are the layer you control.

The sandbox: containment under everything

The sandbox is OS-level isolation around the commands Claude runs (macOS, Linux, and WSL2 - not native Windows). Defaults: commands can write only inside the current project and a temp folder, can read most of the disk, and any network access to a new domain triggers a prompt unless you pre-allow it in settings.

Run /sandbox in a session to see and change its status. A nice side effect: with the sandbox on, sandboxed commands run without permission prompts by default, since the OS already contains the blast radius. Fewer interruptions and more safety at the same time.

Safe defaults for a team

Everything above was your personal setup. The team version has one extra requirement: the safe configuration must be the one people get by default, not the one they remember to apply.

Do this now

Sources and further reading

We set it up with you

Want us to set it up with you, end to end?

Three one-on-one sessions. We train you on your real stack and build your first agents together, until you can run it yourself. You keep everything.