Chapter 8: Permissions & Approval System

Both agents need a way to decide: should this tool call run, or should we ask the user first? The permission system determines the user experience — too restrictive and the agent is annoying, too permissive and it's dangerous.

Codex: Guardian Approval System

Approval Modes

Mode Behavior
never Auto-approve everything (maximum autonomy)
on-failure Auto-approve, but ask if a command fails (deprecated)
on-request Ask for sensitive operations (default)
unless-trusted Ask unless command matches trusted patterns
granular Fine-grained per-command policies

Request Types

The Guardian system uses typed approval requests:

Approval Flow

Tool determines if approval needed
    ↓
Create GuardianApprovalRequest with context
    ↓
Serialize to JSON for human review
    ↓
Wait for user decision (approve/deny)
    ↓
Record decision for audit
    ↓
Optionally update exec policy for future similar operations

Execution Policies

Codex supports declarative execution policies that persist across sessions:

Prompt Integration

Different approval modes inject different instructions into the system prompt:

approval_policy/never.md        → "You may run commands freely"
approval_policy/on_request.md   → "Request approval for sensitive operations"
approval_policy/on_failure.md   → "Retry with approval on failure"

Code Location

Claude Code: Multi-Layer Permission System

Permission Modes

Mode Behavior
default Show permission dialog for each risky operation
auto Use YOLO classifier to auto-approve/deny (no dialogs)
acceptEdits Auto-approve code edits, ask for other operations
bypassPermissions No permission checks (can be remotely kill-switched)
plan Temporary strict mode during planning phase
dontAsk Deny all risky operations (read-only)

Permission Rules

Rules have three behaviors: allow, deny, ask. They come from five base sources (in priority order), plus additional per-session sources:

  1. Policy settings — Org-enforced (highest priority, remote-managed)
  2. Flag settings — CLI arguments
  3. Project settings — Per-project .claude/settings.json
  4. Local settings — Workspace-local config
  5. User settings — Global ~/.claude/settings.json

Additional runtime sources: cliArg, command, session (for one-off approvals during a session).

Rule examples:

"Bash(npm:*)"           → Allow npm commands
"Edit(~/.claude/**)"    → Allow editing claude config
"Bash(!rm:*)"           → Deny rm commands

YOLO Classifier

The "classifier" in auto mode is not a traditional ML model — it's an LLM side query. Claude Code calls the Claude API itself (via sideQuery()) to judge whether a proposed action is safe:

Permission Dialog

In default mode, the user sees an interactive dialog:

┌─ Permission Request ────────────────────────┐
│ Bash: npm install express                    │
│                                              │
│ [Allow]  [Allow Always]  [Deny]  [Deny Always] │
└──────────────────────────────────────────────┘

Enterprise Controls

Code Location

Comparison

Aspect Codex (Guardian) Claude Code (Multi-Layer)
Approval modes 5 modes (never, on-failure, on-request, unless-trusted, granular) 6 modes
Auto-approval Execution policy matching (declarative) LLM side query — Claude judges its own actions
Typed requests Yes (ShellCommand, ApplyPatch, etc.) Per-tool check (generic)
Runtime amendment Model can request new permissions User adds rules via dialog
Enterprise Config-driven Remote-managed with kill switches
Persistence Exec policies (TOML/JSON) Settings files (JSON)
Fallback Deny if no policy matches Ask user if classifier uncertain

Key Design Difference

Codex uses declarative policies — rules are written down and matched against commands. The model can even request new permissions at runtime via the request_permissions tool.

Claude Code uses adaptive classification — an ML model analyzes each command in real-time. This handles novel commands better but is less predictable than pattern matching.