Topic 03

Permissions and Approval Modes

Setup

Every tool call either runs at once or stops and asks you. Permissions are the rules that decide which, and the approval mode is the default a session starts from. Both are enforced by the harness before a tool runs, which makes them different in kind from anything you write in the instructions file.

Each mode is a statement about what you trust: the agent, the environment or only yourself. Some commands belong on no allow-list whatever the mode, and knowing which is most of the skill.

The Vocabulary

A permission is a rule for a kind of tool call, with one of three outcomes. Allow: it runs without asking. Ask: it waits for your yes. Deny: it is refused, and the agent is told so. The allow-list is the set of allow rules and the deny-list the set of deny rules. The approval mode is the session-wide default for any call no rule covers.

As of 2026 most agents have all of these, under their own names and with their own syntax; Chapter 15 has the details for particular tools. Some evaluate every deny rule before any allow rule, so a narrow allow cannot carve an exception out of a broad deny. Check how yours orders them, because the order decides how your rules interact.

A permission prompt (illustrative)
The agent wants to run a command:

    git push --force origin refund-window-12h

  1. Yes
  2. Yes, and don't ask again for commands starting with git push
  3. No, and tell the agent what to do instead

Ask Every Time

In the strictest mode, reads run and every edit and every command waits for you. It is the safest mode and the slowest, and its failure is approval fatigue, the effect Chapter 1 described: by the fortieth prompt the yes comes before the reading, and you approve a force-push the way you approved the previous thirty-nine test runs. The number is an illustration, not a measurement; the effect is familiar to anyone who has clicked through a stack of permission dialogs.

A prompt approved without reading still looks like control, which makes it worse than no prompt. Reading harder does not fix that; fewer prompts do. Allow the calls you would always approve, and the ones left are rare enough to read.

The way to find those calls is empirical. Start a new repository in ask-every-time mode for a few days and note which prompts you approve without reading because there was nothing to read: the test runner, the formatter, git diff. Those are the first allow rules. Anything you hesitated over, even once, stays in ask.

Allow-Lists

Commands you would approve every time without thinking, such as the test runner, the linter, the formatter, git status and git diff, go on the allow-list and run without asking. Everything else asks. Your attention then goes to the rare prompt that matters, and the agent spends less time waiting.

The skill is in the pattern. A rule that allows "any git command" allows git push --force, and a rule that allows the test runner allows any code the agent writes into a test file, because running the tests runs that code. Most tools match rules against the text of the command, and an equivalent command written differently, through a script or a one-line program, may not match a rule meant to catch it. An allow-list is only as safe as the sandbox it runs in, which is the next page.

Watch the standing rules your answers create. Most tools let a prompt be answered with something like "yes, and don't ask again", which saves a rule for that command shape. Approved in a hurry, such an answer can save a rule far broader than the command you were looking at. Review the saved rules the way you review the instructions file, because they are configuration that decides what runs without you.

At CragmoorRuleWhy
The one-file and full test commandsAllowRun twenty times a task; safe only because the sandbox holds no credentials
Type-check, lint, formatAllowRead the code and rewrite whitespace; nothing outside the repository
git status, git diff, git logAllowRead-only, and the agent needs them to see its own changes
Edits inside the repositoryAllow, in the sandboxRecoverable with git from a clean start
Any other commandAskRare enough to read, so each prompt gets a real look
Installing a dependencyAsk, alwaysEvery new package is a supply-chain decision (Chapter 12)
Push, deploy, publish, migrationsDenyEffects outlive a discard; a person does these by hand
Which rule decides a command
CheckedAt CragmoorRulegit push --force origin refund-window-12h
1Push, deploy, publish, migrations: git push *Denydecides: refused
2Installing a dependency: pip install *Asknot checked
3The one-file and full test commands: pytest *Allownot checked
4Type-check, lint, format: mypy * ruff check * ruff format *Allownot checked
5git status, git diff, git log: git status * git diff * git log *Allownot checked
6Any other commandAsknot checked

Auto-Approve

In auto-approve mode everything runs without asking. It is reasonable only where the blast radius is already small: a container that holds the repository and no credentials, a cloud agent on its own branch, a throwaway spike. It is never reasonable on a laptop with access to production.

The mode does not make the agent more careful. It removes the last moment at which you could notice that it was about to do something you did not intend. Whether that moment matters depends entirely on what the worst command can reach, so the decision to auto-approve is really a decision about the environment, made after you have checked it.

Auto-approve also changes what review means for commands. With prompts, each command was checked, however tiredly, before it ran. Without them, the transcript is the only record of what ran, and reading it after the session is the only check. For a spike in a container that is fine. For anything you intend to keep, read the transcript's commands as part of reading the diff.

Never on the List

Some commands stay off every allow-list in every mode, because their effects reach beyond the repository and outlive a discard. Pushing, and above all force-pushing. Deploying. Deleting anything outside the working tree. Publishing a package. Running migrations against any shared database. Installing new dependencies. Sending messages or email. Anything that uses production credentials.

Each of these is denied or always asks. Most of them should also be impossible in the agent's environment, which is the job of the sandbox: a deny rule on git push stops the obvious command, and an environment with no push credentials stops every version of it.

Installing a dependency belongs on this list for a reason that is easy to miss. Agents sometimes name packages that do not exist, and a name that does not exist can be registered by anyone, including someone who wants an agent to install it. Every new dependency is a decision about code from a stranger running on your machine, and Chapter 12 shows how to check one. A prompt is the least you owe that decision.

Matching the Mode to the Task

The mode is chosen per task, not once at setup. The same agent, on the same repository, needs different trust for different work.

Choosing a mode for a task
Mapping unfamiliar code, such as reading pricing to learn how discounts work→Reads allowed, everything else asks
A well-specified change in a sandbox, such as the refund boundary tests→Allow-list, the rest asks
A throwaway spike in a container with nothing real in reach→Auto-approve
Anything on a laptop that can reach staging or production→Ask, and fix the laptop first

As of 2026 many tools also offer a read-only planning mode, in which the agent reads and proposes but edits nothing. It is the natural mode for the first pass over unfamiliar code and for the plan Chapter 5 asks for before any file changes.

Instruction vs Permission

An instruction in the project instructions file asks the model to behave a certain way. It is usually followed, and nothing checks it. Use instructions for conventions.

A permission is enforced by the harness before the tool runs, and no wording in the context gets past it. Use permissions for anything whose violation would cost more than a discarded diff.

Misconceptions
  • "Approving each command keeps me in control." Only while you read each one. Approval fatigue turns the fortieth prompt into a reflex, and an allow-list for the safe commands keeps your attention for the rare prompt that matters.
  • "Allowing the test runner is safe because tests are harmless." The agent can put any code in a test and run it. The permission amounts to "run any code", bounded only by the sandbox.
  • "A deny rule on deleting files stops deletion." The same effect is one different command away: a script, a one-line program, another tool. Deny rules close the obvious path, and the sandbox bounds the rest.
  • "Auto-approve is for experts." It is for environments where the worst command is cheap. Expertise does not shrink the blast radius.
  • "The instructions file can forbid commands." It can ask. Only a permission or the sandbox enforces.
Why It Matters
  • Allow the read-only and checking commands, deny the irreversible ones, and let everything else ask. Your attention then goes to prompts rare enough to read.
  • Write allow rules as narrow patterns: the test runner on the test directory, not any command that starts with git.
  • Keep push, deploy, publish, install and anything holding production credentials off every allow-list. Those are the commands whose mistakes outlive a discard.
  • Choose auto-approve only inside a sandbox you have checked. The mode trusts the environment, not the agent.

Knowledge Check

Kai adds an allow rule for any command that starts with git, to stop the prompts. What has he actually allowed?

  • Read-only git commands, such as status, diff and log
  • Every git command, including a force-push to the shared repository
  • Git commands that change local branches but never the remote ones
  • Only git commands that Kai has already approved once by hand

Why is allowing the test runner broader than it looks?

  • The test runner deploys the code to staging after a green run
  • The test runner reads every credential file on the machine
  • It runs whatever code the agent has written into the tests
  • Allowing one command disables the deny rules for the session

The rule "never edit the migrations directory" must hold even if the agent misreads a task. Where should it live?

  • A deny rule for edits there, with the reason in the instructions file
  • A line in the instructions file, stated firmly and in capital letters
  • A sentence repeated at the start of every task you give the agent
  • A comment at the top of each migration file explaining the rule

Which setup makes auto-approve a reasonable choice?

  • An experienced engineer's laptop, because they know what they're doing
  • Any laptop, as long as the task is short enough to finish in minutes
  • A container holding only the repository and no credentials at all
  • A container with the staging credentials mounted for the test runs

What does approval fatigue do to the value of each prompt?

  • It makes the harness skip prompts once you have approved many in a row
  • It turns each prompt into a reflex yes that still looks like control
  • It makes each later prompt more careful, since you know the pattern
  • It leads the agent to ask fewer questions, so prompts become rarer

You got correct