Build your own Claude Code
The permission engine·25 min

Permission modes

0 / 1
# grade this stage (from your course directory)
npx theinference test --stage modes --watch

You can match a rule. Now turn that into a verdict. decide(settings, call) returns allow | ask | deny by walking the precedence you learned in step 01: check deny, then ask, then allow, and if no rule matched, fall through to the active mode's default. This one function is the heart of the permission engine — step 04 adds protected paths and step 05 wires it into the loop.

What to build

Your task

Implement decide

Implement decide(settings, call) in src/permissions.ts. In order: if any settings.deny rule matchRules the call, return 'deny'; else if any settings.ask rule matches, return 'ask'; else if any settings.allow rule matches, return 'allow'; else apply the mode default for settings.defaultMode (default 'default'). The mode default: read-only tools (Read/View/Glob/Grep) → 'allow'; then bypassPermissions → 'allow'; plan → 'deny' (side effects blocked); acceptEdits → 'allow' for write tools (Write/Edit), else 'ask'; default → 'ask' on any write or bash. The tests/adapters.ts adapter forwards to it.

tests/adapters.ts
import { decide, type PermissionSettings, type ToolCall, type Decision } from '../src/permissions'

export function runDecide(settings: PermissionSettings, call: ToolCall): Decision {
  return decide(settings, call)
}
Mode defaults (only reached when NO rule matched)
mode               read-only   write/edit   bash/side-effect
default            allow       ask          ask
acceptEdits        allow       allow        ask
plan               allow       deny         deny
bypassPermissions  allow       allow        allow
How it's graded

Process mode runs program.ts decide over a {settings, calls[]} matrix and compares the allow|ask|deny vector to expected.json. The matrix crosses each mode with read/write/bash calls and with deny/ask/allow rules present — including the override traps: a deny rule under bypassPermissions still denies; an allow rule under plan still allows. Every cell must match the reference.