Skip to content

Choosing a permission mode per task

In this lesson we give a coding agent the same small task twice. The first time it asks before every edit and every command. The second time it edits without asking and only stops for commands. We count the prompts in each run and read what they were for. Then we decide which mode the task deserved. The setting is the to-do fixture from Your first session with a coding agent, committed to a throwaway git repository, where a wrong edit costs one git checkout.

The mode names and flags here are Claude Code’s, checked against the vendor’s documentation on the date at the end of the lesson [1]. Other coding agents have the same levels under other names. The reasoning transfers, and the exact flags may not.

In your first session the agent asked before it edited a file, and you approved one line at a time. That behavior is a setting. Permission modes are preset levels of how much the agent may do without asking, from approving every action to running unattended. The mode sets the baseline for the session, and the allowlists you write in the next lesson widen or narrow it per command. Which mode a fresh session starts in depends on your plan and your settings. On some plans the built-in starting mode is auto, so check the status bar before you assume the agent asks [1].

Claude Code’s modes, with what runs without a prompt in each. The last column is our paraphrase of the vendor’s advice on when to use it [1].

Mode (config value)Runs without askingWhen the vendor suggests it
default (Manual)ReadsYou want to see each action, or the work is sensitive
acceptEditsReads, file edits in the working directory, and file commands such as mkdir, mv and cpCode you read back afterwards
planReads and exploratory shell commands. Edits are blocked until you approve a planUnderstanding a codebase before you change it
autoEverything a second model, the classifier, approvesLong tasks where the prompts wear you down
dontAskReads and pre-approved tools. Anything that would prompt is denied insteadCI and scripts with an exact allowlist
bypassPermissionsEverything, apart from the few actions listed belowOnly inside a container or virtual machine that isolates it

The acceptEdits and bypassPermissions rows have fine print that matters for this lesson. acceptEdits approves an edit only when the path is inside the working directory, and any shell command outside the built-in read-only set still prompts, so the test run in our task stops for you in that mode too. bypassPermissions skips the permission prompts, including for writes to protected paths such as .git that the other modes guard. A few actions still prompt in it: a tool matched by an ask rule you wrote, and a tool that needs your answer to work. The vendor’s own page limits the mode to isolated containers and virtual machines, and the tool refuses to start in it as root or under sudo, “for security reasons”, as the vendor puts it [1].

You pick the mode for one session with a flag, claude --permission-mode acceptEdits, or cycle through the modes in a running session with Shift+Tab. A defaultMode entry in a settings file sets where every session starts, with one exception: auto and bypassPermissions in a project’s settings files don’t take effect, so a repository can’t check in a setting that starts every clone in a hands-off mode [1]. This lesson uses the flag. Each run then states its mode in the command that started it.

Here is the decision as a small program. NO_PROMPT holds the table above for the three kinds of action our task uses, and TASK is the task as the agent most often does it: two reads, two edits, one command. The complete file is site/examples/customizing-agents/permission-modes/modes.py in the repository.

NO_PROMPT = {
"default": {"read"},
"acceptEdits": {"read", "edit"},
"bypassPermissions": {"read", "edit", "run"},
}
TASK = [
("read", "todo.py"),
("read", "test_todo.py"),
("edit", "todo.py"),
("edit", "test_todo.py"),
("run", "python3 -m unittest -q"),
]
def prompts(mode, actions):
return [f"{kind} {target}" for kind, target in actions if kind not in NO_PROMPT[mode]]
Checkpoint · predict

What does this print, one line per mode?

for mode in ("default", "acceptEdits", "bypassPermissions"):
count = len(prompts(mode, TASK))
noun = "prompt" if count == 1 else "prompts"
print(f"{mode}: {count} {noun}")

Output verified in CI from site/examples/customizing-agents/permission-modes/modes.py.

The program is a model. The real agent may edit a file twice or run an extra command, and each of those adds a prompt in the modes that ask for it. Reads don’t change the tally, because no mode prompts for a read inside the working directory. Your counts in the two runs below can differ from the model by one or two. The comparison stays the same: every edit and every command prompts in Manual mode, only the commands prompt in acceptEdits, and nothing prompts in bypassPermissions.

Make a fresh copy of the fixture directory, site/examples/coding-with-agents/first-session/fixture-repo/, outside the course repository, and change into it. The copy has no git history of its own, so give it one before the agent touches anything. This commit is the point you reset to between the runs.

Terminal window
git init -q && git add -A && git commit -q -m "fixture"

Run the tests next. One of them fails on purpose, because that bug is the first-session lesson’s task, and you want to know that before the agent tells you.

Example · run it

Run this and compare the last line with the output below.

Terminal window
python3 -m unittest -q
Output
FAILED (failures=1)

Output verified in CI from site/examples/coding-with-agents/first-session/tests.py.

Start the agent in Manual mode, claude --permission-mode default, and send this brief.

Add an `undo` command to todo.py that marks item N as not done, the
mirror of `done`. Add one test for it to test_todo.py. Then run
`python3 -m unittest -q`. One test, test_done_marks_the_numbered_item,
already fails and is not your task. Leave it. Do not edit todos.json.

Now count. Keep a tally of every prompt, and for each one write down what it asked to do: which file, or which command. Approve each one after you have read it. Expect an edit to todo.py, an edit to test_todo.py and one command, and don’t be surprised by a second edit to the same file. The agent also reads both files first, and those reads never prompt.

When the agent reports done, read the diff with git diff and check the tally against it. Every changed file should have a prompt in your list. Then reset the fixture to the commit you made with git checkout -- . so the second run starts from the same place.

Start the agent again, this time with claude --permission-mode acceptEdits, and send the same brief. The status bar reads accept edits on. Tally again.

This time the two edits are written without a prompt, and the session stops once, at the test command. The vendor’s guidance for this mode is to review the changes afterwards in your editor or with git diff, rather than approving each edit inline [1]. Do that now. Read the diff as carefully as you read the prompts in run one, because this is the first time you see what changed.

Now compare the two runs on one question: what would a mistake have cost? In run one, a wrong edit shows up in a prompt before it is written, and you decline it. In run two, the same wrong edit is written, and you find it in the diff. The fixture is a committed copy you reset with one command, so in both runs the repair costs the same git checkout. The mode changed when you saw the edit, and the place decided how much a late look could cost. Choose the mode by what a mistake costs in the place the agent works, and remember the blast radius habit from the safety course: say out loud what the agent can reach before you press enter.

Checkpoint · scenario

The undo task went well in the fixture. You want the same change in your team’s repository, where you have half a day of uncommitted work in the working tree. Which mode do you start with, and what do you do first?

The vendor’s course on running the tool unattended makes the same point from the other side: hands-off runs belong in an environment built to be thrown away, such as a container, and the check afterwards is the review of what it produced [2]. The mode is the last thing you choose, after you know where the agent works and what a wrong action there would cost.

Checkpoint · sort

Place each task in the mode you would start it in.

Exercise

Do the two runs from this lesson, if you haven’t already, in a fresh copy of the fixture with its own first commit: once in Manual mode and once in acceptEdits, with the same brief. For each run write down the number of prompts and what each one asked for. Then write one line that names the mode you would use for this task in this place, and why. The point is to practice choosing a mode from what a mistake costs, before you do it in a repository that matters.

A good result: the Manual tally has one entry per edit and per command, the acceptEdits tally has only the command, both diffs contain the same change, and your one line mentions where the agent worked and what a wrong edit would have cost there. Reflection: in which of your own repositories would the answer be different, and what’s in them that makes it so?

Stretch: Run the task a third time in plan mode and note where the agent stops: it reads and proposes, and the edits wait until you approve the plan.

Recap

  1. A permission mode is a preset for what the agent may do without asking. In Claude Code, default prompts for every edit and command, acceptEdits approves edits inside the working directory and still prompts for other commands, plan blocks edits, and bypassPermissions skips the permission prompts apart from your own ask rules and the tools that need your answer [1].
  2. The mode sets the baseline, and allowlists refine it per command. Deny rules hold in every mode, and allow rules do nothing in bypassPermissions.
  3. Choose the mode by what a mistake would cost in the place the agent works, and say the blast radius out loud first.
  4. Step a mode up only inside a sandbox or a container, and only as far as the task in front of you needs. A worktree or a branch isn’t isolation.
  5. In a mode that skips prompts, the diff is your review. Read it as carefully as you would have read the prompts.

You can now

  • Sets permissions to the least the work needs

  1. Anthropic. Choose a permission mode. Claude Code documentation. Reference. Claude Code permission modes
  2. Anthropic. Claude Code in action. Claude Academy. Course. Academy claude-code-in-action