Skip to content

Capabilities

Control

Every mutating tool call clears a rule before it runs — and when the rules can’t decide, the answer is no.

One choke point

The runtime’s tool dispatcher checks the permission engine and returns a denial before a tool’s execute is ever reached. There is no second path into a tool, so there is no route around the check.

Read-only tools — read, grep, glob, ls — pass without a prompt, because asking about every file read would make the default mode unusable. fetch is deliberately not on that list: it reads nothing local but sends data to an arbitrary host, so it is gated like a mutating tool. Anything that reaches the ask step with no permission requester configured resolves to deny, never to “assume it’s fine.”

A permission prompt in an arcturn session: editing src/routes/signup.ts requires approval, with allow, deny, and always-allow for src/**.ts offered.

Rules, scopes, resolution

A rule is four fields: a tool name (or *), a specifier matched against the call’s subject, an action of allow, deny or ask, and a scope. Specifiers come in three forms — a command prefix like git *, a glob like **/*.ts, or an exact string.

Scope precedence is session over project over user, with a specificity tiebreak inside a scope and deny winning a tie. One deliberate exception: a more specific deny beats a broader permissive rule even from a nearer scope, so a checked-in project config cannot escalate its own privileges just by being cloned.

Approving a prompt with always allow persists the suggested rule — a bash subject is widened to its first word plus *, other tools default to their exact subject — into the project config.

.arcturn/config.json
{
  "tool": "bash",
  "specifier": "git *",
  "action": "allow",
  "scope": "project"
}

Four modes

A mode is the posture the engine falls back to when no rule matched. Switch at runtime with /permissions in the CLI, or agent.setPermissionMode(mode) from code.

Plan mode is enforcement, not etiquette: its check runs before rules are evaluated, so no stored allow rule — however specific, however recently added — can let a mutating tool through while it is active.

default
Read-only tools run freely; everything else is asked about unless a rule already settles it.
acceptEdits
Like default, but write, edit and multiedit are also auto-approved.
plan
Only read-only tools may run; every mutating tool is denied outright.
yolo
Everything is auto-approved — for sandboxes and CI, not your laptop.

Dry run and the shadow tree

--dry-run is plan mode for files. The agent works normally, but every file mutation is redirected into a shadow copy of the workspace under ~/.arcturn/overlays/<sessionId>/. Review one aggregate diff with /diff, then /apply to land it or /discard to throw it away.

The limit, stated plainly: --dry-run deliberately does not wrap bash, grep or glob — they take commands and patterns rather than a single path — so a shell command still reads and mutates the real tree while dry-run is active.

Hooks with veto power, and the OS sandbox

Lifecycle hooks are shell commands declared at preToolUse, postToolUse, sessionStart and runEnd. Only a preToolUse hook can block anything, and only the call it ran for — the lifecycle event arrives as JSON on the hook’s stdin, so the hook can decide on the actual arguments rather than a tool name.

The sandbox is a separate, opt-in layer, and it governs bash rather than the edit tools. Set to workspace-write, the command is wrapped by an OS-level sandbox — sandbox-exec on macOS, Bubblewrap on Linux — that denies file writes everywhere except the working directory, the OS temp directory and $HOME/.arcturn. Reads, network and process spawning are left alone: this narrows write access only.

.arcturn/config.json
{ "sandbox": "workspace-write" }

Speculative approval

A permission prompt stops the agent dead, and every second you take to answer is idle time. With speculative approval the agent keeps working while the prompt sits in front of you, with every file mutation landing in a shadow overlay keyed to that pending request. Approve and the shadow is applied instantly; deny and it is thrown away, leaving the workspace bit-for-bit what it was.

Only write and edit are speculatable, because only file mutations can be undone by throwing a directory away. Everything else — bash, fetch, websearch, any MCP tool, sub-agents — is blocked outright for as long as a speculation is open, and nothing is ever applied implicitly: a timeout, a dropped connection or a process exit all discard.

Every turn counts.

Start a session, watch every tool call ask first, then go back and read exactly what happened.

npm install -g arcturn