#+TITLE: Comparative Safety/Permission Study — Agent Authorization Architectures
#+FILETAGS: :notes:comparative-study:safety:permissions:security:

* Purpose

Compare safety architectures across Claude Code, OpenCode, OpenClaw, and Hermes Agent against Passepartout's 10-vector dispatcher. Inform the HITL regime, auto-approve learning, and permission dialogs in v0.7.2 and dispatcher-learn in v0.9.0.

* Findings Summary

| Dimension | Claude Code | OpenCode | OpenClaw | Hermes | Passepartout |
|-----------+-------------+----------+----------+--------+--------------|
| Modes | 7 (default, acceptEdits, plan, bypass, dontAsk, auto, bubble) | 3 per-tool (allow/deny/ask) | 3-tier (config/gateway/tool) | 3 (manual/smart/off) | Single HITL flow |
| Auto-approve | AI classifier (Opus 2-stage XML) | Rule evaluation (last-match-wins) | Exec approval manager (promise-based) | Smart approval via aux LLM | Planned: dispatcher-learn |
| Non-bypassable floor | Path safety checks immune to bypass | None | Gateway HTTP tool deny + config drift | 12-item hardline blocklist | 10 deterministic vectors |
| Remember/always | Session-level settings files | In-memory (session-only) | allow-always + config persistence | Session + permanent config.yaml | Not implemented |
| Pre-tool hooks | PreToolUse (27 lifecycle events) | None | None | pre/post approval hooks | defskill triggers only |
| Anti-misclick | Not literal 200ms; denial tracking + mode stripping | No explicit protection | No explicit protection | Countdown timer on prompt | Not implemented |
| Sandbox | bubblewrap+Seatbelt | None | Docker with 30+ blocked paths | None (container bypass) | Regex + planned bwrap |

* Claude Code — Authorization Pipeline

**7 Permission Modes:**
| Mode | Description |
|------|-------------|
| default | Interactive prompting for every tool use |
| acceptEdits | Auto-allow edits within cwd; prompt for bash/outside |
| plan | Plan-only; can plan but not execute |
| bypassPermissions | Full bypass (can be disabled via GrowthBook) |
| dontAsk | All ask results → deny; only rule-allowed tools |
| auto | AI classifier (Opus) decides yes/no on every invocation |
| bubble | Internal (not user-facing) |

**Authorization Pipeline** (12 steps in hasPermissionsToUseToolInner):
1a. Tool denied by rule → DENY immediately
1b. Tool has ask rule → ASK
1c-1g. Checks: permissions, implementation deny, user interaction required, content-specific rules, safety checks (.git/, .claude/, shell configs — bypass-immune)
2a. BypassPermissions or Plan → ALLOW
2b. Always-allow rule → ALLOW
3. Passthrough → ASK

**Auto-Mode Classifier** (yoloClassifier.ts):
- 2-stage Opus XML: Stage 1 (fast, max_tokens=64, <block>yes/no</block>), Stage 2 (thinking, chain-of-thought)
- Input: serialized transcript of user messages + assistant tool_use blocks (assistant text excluded — could manipulate)
- Fail-closed by default (GrowthBook iron_gate), but can fail-open for dev
- Transcript-too-long → fall back to manual prompting
- Denial tracking: 3 consecutive / 20 total blocks → force human review
- Safe-tool allowlist: FileRead, Grep, Glob, LSP, Task*, TodoWrite, AskUserQuestion — auto-allowed without classifier
- acceptEdits fast-path: re-checks tool with acceptEdits mode before calling classifier
- Mode stripping: dangerous rules (Bash(*), PowerShell(*), Agent) auto-removed when entering auto mode

* OpenCode — Permission Architecture

Simpler, rule-evaluation based. 3 actions per permission type (allow/deny/ask) with glob patterns:
```yaml
permissions:
  bash: "ask"
  edit:
    "*.md": "allow"
    "*.env": "deny"
```

Pipeline: evaluate each pattern → if deny → DeniedError; if all allow → auto-allow; otherwise → needAsk → publish Event.Asked → block until reply.

**Always Allow**: User clicks "Always allow" → patterns added to PermissionTable (SQLite/Drizzle). Auto-resolves any pending permissions the new rules cover. Session-level only (runtime, not written to config).

**Question prompts**: Vim-style (hjkl) navigation. Numbers 1-9 for direct selection. Multi-tab for multi-question. Custom answer textarea.

**Cascading rejection**: Denying one permission auto-rejects all pending permissions for that session.

* OpenClaw — Gateway-Centric Security

**Gateway-level access control** — all tool invocations flow through central auth/approval server:
- Auth modes: none/token/password/tailscale/device-token/bootstrap-token/trusted-proxy
- Rate limiting, browser origin checking, timing-safe secret comparison

**Exec Approval Manager**: Promise-based approval queue with allow-once (one-shot consumption), allow-always, 15s grace period for late awaiters.

**Dangerous config flags audit**: Scans configuration at startup for security risks (SSRF, unrestricted filesystem access, Docker privilege escalation). Plugins declare their own dangerous flags.

**Sandbox**: Docker-based with 30+ blocked host paths, blocked home subpaths (.ssh, .aws, .docker, .gnupg), blocked network modes, blocked seccomp/apparmor profiles. Tool policy separate for sandboxed agents.

**Node invoke approval**: Device-identity-bound, client-identity-bound, backend-bridge for web UI, allowlist for forwarded params.

* Hermes Agent — Three-Tier Detection

**HARDLINE blocklist** (12 patterns, unconditional — not even --yolo can bypass):
rm -rf /, mkfs, dd of=/dev/sd*, fork bombs, kill -1, shutdown, reboot, etc.

**DANGEROUS patterns** (47 patterns, approvable):
rm -r, chmod 777, chown -R root, curl|bash, systemctl, git push --force, sensitive file writes, self-termination, etc.

**Approval flow** (check_all_command_guards):
1. Skip containers → auto-approve
2. HARDLINE check → block
3. YOLO/mode=off → auto-approve (except hardline)
Phase 1: Tirith security scanner (Rust binary, cryptographically verified) + pattern detection
Phase 2: Smart approval via aux LLM (if mode=smart)
Phase 3: Manual approval with timeout (default 60s)

**Busy mode**: interrupt (immediate), queue (next turn), steer (inject after next tool call)

**SUDO injection**: Transparent sudo -S -p '' rewrite with password piped via stdin from .env.

* Passepartout Blindspot Assessment

1. **No "remember" mechanism** — Every HITL prompt requires a decision. Claude Code auto-approves read-only tools via allowlist. Hermes saves "always" approvals to config.yaml. Passepartout should add per-session and permanent allow options. [Action: v0.7.2 HITL inline]

2. **No non-bypassable floor** — Passepartout could add a hardline blocklist for catastrophic commands (rm -rf /, mkfs, dd to devices) that cannot be approved. [Action: v0.7.2, add to dispatcher-check-shell-safety]

3. **No classifier** — Claude Code and Hermes both use auxiliary LLMs to reduce HITL frequency. Passepartout's dispatcher-learn (v0.9.0) uses deterministic counting instead. This is architecturally cleaner but will ask more questions initially. Consider adding a safe-tool allowlist for read-only tools. [Action: v0.7.2, add tool-safety classification]

4. **No anti-misclick** — Claude Code tracks denials; Hermes has countdown timers. Passepartout could add a 500ms input block after HITL prompts appear. [Action: v0.7.2 HITL inline]

5. **Sandbox superiority** — Passepartout's planned bwrap is better than OpenCode (none) and Hermes (none), comparable to Claude Code (same bwrap approach). OpenClaw uses Docker which is heavier. [Architecture confirmed]

6. **Hook system missing** — All 4 competitors have PreToolUse/PostToolUse hooks. Passepartout's skills only fire on definable triggers; they can't intercept tool execution. [Action: add to Extension Architecture Study]
