Permissions Are A Runtime, Not A Popup
The runtime decides whether a tool runs, with a ladder of rules and then a race between answerers. Whatever the ladder does not settle falls to the race: you, a hook, an automatic check, or a phone. The first answer wins.
I built the confirmation box first and thought that was the job. The answer comes from six different places, and the question outlives the terminal it started in.
Permission loop
Put a traffic light at the door between the agent and the real world. Every action it wants to take waits at the light.
Green sends the action straight through, like reading a file. Yellow stops it and asks you first. Red is never, no matter who asks. Safe work flows. Risky work waits.
The light takes its answer from several places at once. A house rule, a project setting, and your typed yes all reach it. So does a tap on your phone when you are nowhere near the desk.
Follow one tool call through. It passes a short ladder of fast checks in order. A clear allow or deny ends it there. Anything left over falls to the ask path, which is a race. Every answerer starts at the same time, and the fastest one settles it.
01Modes are the start, not the system
A mode sets how strict the permission system is for the session. The careful default adds no automatic allow. Plan mode holds off every change, and accept-edits waves plain file edits through. Bypass mode runs what you already trust, and a never-ask mode turns every question into a refusal. An automatic mode runs a safety check in place of the question.
The verdict comes from the mode plus the rules, the tool, the argument, the situation, and any hooks. Asking which mode is on names one input. Walking the whole decision names all of them.
02The ladder runs before anything is shown
A hard deny rule ends the call on the first rung. An always-ask rule stops it, and so does a touchy path like your git internals or shell config. A trusted mode can allow the call, and a standing allow rule can too. Whatever is left drops to the ask path, and that is where the light turns yellow.
The guard on a touchy path still stops and asks, even under bypass mode. The never-ask mode runs dead last, after every other check. It takes any question still standing and turns it into a refusal, so nothing slips past.
03Rules come from many places and target many shapes
A rule says allow, deny, or ask. Your own settings hold rules. So do the project settings, your machine, your company policy, a command-line flag, and this one session. A rule can point at a whole tool. It can also point at a shape like any npm command, an outside server, or a kind of subagent.
Rules stack instead of overwriting each other. A company can forbid one action while your session allows another, and neither erases the other. The session rule aims at something narrow. The company rule holds its ground underneath.
04A hook can change the shape of the work
A hook is a program the runtime calls before the tool runs. It can allow the action, block it, or halt the whole run. It can also change what the action does, or write a new rule for next time. A hook can approve a call and hand back a different command.
The runtime keeps four versions of one call apart. The model asks for one thing. The hooks see the raw input, the transcript stores a tidied copy, and the tool runs a fourth version. Those four diverge the moment a hook rewrites the command.
I got this wrong early. I read the transcript and assumed the hooks judged that text. The hooks judge the raw input the model sent. Keep the split, and an audit can still name what ran and why.
05The ask path is a race
When a call reaches the ask path, five answerers wake up at once. You sit at the keyboard. Hooks run in the background. An optional automatic safety check evaluates the command. The web app answers when you drive the session from a browser. A chat relay carries the question out over a messaging app and reads back a clean yes.
One guard settles the race, so exactly one answer lands and the rest are dropped. A mode change while the question is open forces a fresh check. The web app can flip a setting while your terminal shows the question, and the runtime re-checks.
Why the question travels
You can start the agent from a terminal, a browser, or a phone. So the question cannot stay tied to one screen. It has to travel, hold its place, and take an answer from whichever screen replies first. Every screen that can answer joins the race.
06The automated check is a branch under policy, not the boss
An automatic check can approve a call without you. The rules still set what counts as safe, and the check runs inside a fenced lane. Plainly safe actions, mostly reads and small bookkeeping, skip it. The guard on a touchy path sits above it.
Some shell commands need your yes before the check will touch them. When the check is unavailable, the runtime can refuse outright and tell you why. When the conversation runs too long for the check to read, the call falls back to asking you. With no one available to ask, it stops instead of guessing.
Know how far the check reaches before you lean on it. An automatic yes is easy to oversell. It approves inside a bounded list of safe cases, and the rules set that list.
07For subagents, permission is part of the job setup
The main agent sends a subagent off to do a job. Its permission settings are fixed before it starts and frozen while it runs. It can bring its own mode, unless the parent already runs a more trusting one. Its allowed-tools list limits what it can touch. A subagent with no way to show a question answers no rather than freeze. A subagent that can show a question waits for the automatic checks to finish first.
Scope the subagent at the moment you create it. A job that runs unattended has no second chance to ask.
The cost
This width costs you visibility. You see one question while rules, hooks, and an automatic check already shaped the answer behind it. A refusal you did not see coming reads like the model breaking.
The runtime pays for that by keeping the reason behind every answer. It holds every new screen to the same rules, the phone, the chat relay, and the background subagent. Let one screen skip the ladder and no one can say why a call ran.
Decision
If you build one of these, judge its safety by walking the path to the light. Run one action through it and answer three things. Name the place that decided the call. Say whether a hook rewrote the command on the way. State what happens with no person in the room.
Three clear answers mean you built a runtime. One limit sits behind every decision above: a window that holds only so much. Walk that one next.