# Permission Policy

**Purpose:** Capture the intent, mechanism, and known failure modes of Tyler's "bypass permissions everywhere" policy. This file is the single source of truth for *why* bypass mode is the default across every Claude Code session Tyler runs, and *how* that default is actually delivered given upstream bugs.

---

## The Intent

**Every Claude Code session Tyler runs launches in `bypassPermissions` mode.** No prompts on routine operations. This aligns with `autonomous-authority.md`, `master-control-system.md`, `IDENTITY.md`, and the auto-memory `feedback_autonomous_execution.md` — the policy is "act decisively, never ask permission for routine work."

Anthropic's security stance on `bypassPermissions` (verbatim from the permission-modes docs):

> `bypassPermissions` mode disables permission prompts and safety checks so tool calls execute immediately. Writes to protected paths are the only actions that still prompt. Only use this mode in isolated environments like containers, VMs, or devcontainers without internet access, where Claude Code cannot damage your host system.
>
> **Warning:** `bypassPermissions` offers no protection against prompt injection or unintended actions.

**Tyler's explicit decision:** accept the tradeoff. His WSL2 machine is his personal dev environment. Every repo in `~/dev/` is his own code. He does not run Claude Code against untrusted third-party repos, untrusted MCP servers, or network-mounted filesystems. The productivity gain from zero permission prompts outweighs the prompt-injection risk in his specific context. Future-me should NOT second-guess this decision unless Tyler's threat model changes.

---

## The Mechanism (defense in depth, 4 layers)

Bypass mode is delivered through four independent layers. Any one layer failing should not bring back permission prompts.

### Layer 1 — Shell alias (PRIMARY, updated 2026-04-20 for Claude Code 2.1.114)

`~/.bashrc` contains:
```bash
alias claude='claude --permission-mode auto --dangerously-skip-permissions'
```

**Why auto mode is primary in 2.1.114+:** As of Claude Code 2.1.78+, the binary contains a hardcoded protected-path gate that exempts only `.claude/commands` and `.claude/agents` — NOT `.claude/skills`, `.claude/rules`, `.claude/hooks`, `.claude/CLAUDE.md`, or `~/.claude/settings.json`. `--dangerously-skip-permissions` does NOT override this gate (issues #37157, #38806). Writes to those paths prompted on every edit despite all 4 config layers being correct.

Auto mode (shipped 2.1.83, expanded for Max + Opus 4.7 in 2.1.111) replaces prompts with a Sonnet 4.6 classifier. Per docs, **edits inside the working directory skip the classifier entirely**, and `.claude/**` edits route through the classifier instead of prompting. Max plan + Opus 4.7 + Anthropic API (not Bedrock/Vertex) required — Tyler qualifies.

`--dangerously-skip-permissions` still stacks with auto mode for non-protected-path fast bypass. Keep both in the alias.

### Layer 2 — Global `settings.json`

`~/.claude/settings.json` contains:
- `permissions.defaultMode: "bypassPermissions"` — intended persistent activation (unreliable but free to set)
- `permissions.allow: [Bash, Read, Edit, Write, Glob, Grep, WebFetch, WebSearch, Agent, mcp__*]` — explicit allow list as belt-and-suspenders for when `defaultMode` is ignored
- `skipDangerousModePermissionPrompt: true` (top-level, NOT inside `permissions`) — suppresses the "are you sure you want to enter bypass?" dialog on launch

### Layer 3 — `PermissionRequest` auto-approve hook (SCHEMA CORRECTED 2026-04-20)

`~/.claude/settings.json` `hooks.PermissionRequest` auto-approves any permission prompt that slips through:

```json
"PermissionRequest": [{
  "matcher": "",
  "hooks": [{
    "type": "command",
    "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\"},\"reason\":\"auto-approved via user policy\"}}'"
  }]
}]
```

**Schema note:** The correct JSON shape for PermissionRequest is `decision.behavior`, NOT `permissionDecision`. Issue #19298 documents that `permissionDecision` is the PreToolUse schema — emitting it on PermissionRequest silently no-ops. Earlier versions of this rule had the wrong schema; corrected 2026-04-20.

**Why:** This is the failsafe for the subagent propagation bug (issue #40241) — bypass mode doesn't propagate to subagents spawned via the Agent tool, so they still prompt. This hook catches those prompts and auto-approves them. Does NOT catch protected-path prompts — those fire BEFORE the hook. Auto mode (Layer 1) handles that path.

### Layer 4 — Per-project `.claude/settings.json`

Every repo under `~/dev/` has a committed `.claude/settings.json` containing the canonical template (see below). This makes bypass survive a fresh `git clone` — without this layer, only the gitignored `settings.local.json` holds project-level bypass config, and new clones lose it.

---

## Canonical `.claude/settings.json` Template (project scope)

Every new project created under `~/dev/` MUST include this file, committed:

```json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "defaultMode": "bypassPermissions",
    "allow": [
      "Bash",
      "Read",
      "Edit",
      "Write",
      "Glob",
      "Grep",
      "WebFetch",
      "WebSearch",
      "Agent"
    ],
    "deny": [],
    "ask": []
  }
}
```

**Notes on the template:**
- **Do NOT include `skipDangerousModePermissionPrompt`** — that field is *ignored* in project-level `settings.json` (per Anthropic docs, to prevent untrusted repos from auto-bypassing the confirmation). It only takes effect in user or local scope.
- **Do NOT include `mcp__*`** — project scope typically doesn't need MCP access; global scope already has it. Adding it here is harmless but unnecessary.
- **`deny: []` is explicit** — shows intent. Repos with secrets can add to the deny list (e.g. `"Read(//.env*)"`) without touching `defaultMode`.
- **No project-level `settings.local.json` is required** — that's gitignored, user-scope, not part of the committed contract.

This template is piece #6 of the project-level agent contract. See `~/.claude/rules/project-level-agents.md`.

---

## Known Bugs (as of Claude Code 2.1.114, 2026-04-20)

These bugs are why bypass mode needs 4-layer defense-in-depth instead of a single config knob. All issues are filed at `github.com/anthropics/claude-code` and are **open** as of this writing.

| Issue | Severity | Description | Workaround in this policy |
|---|---|---|---|
| #37157 | CRITICAL | Hardcoded protected-path gate in 2.1.78+ binary exempts ONLY `.claude/commands` and `.claude/agents` — NOT `.claude/skills`, `.claude/rules`, `.claude/hooks`, `.claude/CLAUDE.md`, or `~/.claude/settings.json`. Writes to those prompt on every edit. Cannot be overridden by settings.json, CLI flag, or hook. | Layer 1: `--permission-mode auto` routes protected paths through classifier instead of prompting |
| #38806 | HIGH | Feature request for opt-in protected-path override. Open since early 2026 with no Anthropic response. | Auto mode is the current mitigation |
| #34923 | HIGH | `defaultMode: "bypassPermissions"` in `settings.json` silently ignored. Confirmed 2.1.72 → 2.1.114. | Layer 1 (CLI flags via shell alias) |
| #40241 | HIGH | `--dangerously-skip-permissions` does NOT propagate to subagents spawned via the Agent tool. Fixed for team-leader→teammate inheritance in 2.1.101 but Agent-tool subagents still affected. | Layer 3 (PermissionRequest auto-approve hook) |
| #19298 | HIGH | PermissionRequest hook schema divergence — emit `decision.behavior`, NOT `permissionDecision`. The latter is PreToolUse schema and silently no-ops on PermissionRequest events. | Layer 3 hook corrected 2026-04-20 |
| #29026 | MEDIUM | Claude Desktop stores its permission mode in Electron LevelDB and passes `--permission-mode` as subprocess arg, overriding `settings.json`. Also silently disables bypass on SMB/NFS/UNC network mounts. | Avoid network-mounted repos; Desktop is not Tyler's primary surface |
| #37029 | LOW | Bypass mode still prompts for edits to `~/.claude/settings.json`. Subsumed by #37157. | Auto mode handles |
| #20264 | LOW | Inverse feature request — more restrictive subagent modes. Irrelevant to Tyler. | N/A |

**Version timeline:**
- 2.1.78 — protected-path gate introduced
- 2.1.83 — auto mode shipped (initially limited)
- 2.1.101 — `--dangerously-skip-permissions` team-leader inheritance fix
- 2.1.110 — PermissionRequest hook updatedInput re-check
- 2.1.111 — auto mode expanded for Max + Opus 4.7 (Tyler's qualifying version)
- 2.1.113 — Native binary replaces bundled JS
- 2.1.114 — Permission-dialog crash fix when teammate requests access

Auto mode is Anthropic's stated replacement for `--dangerously-skip-permissions` ("legacy behavior rather than a stable foundation" per Anthropic Engineering blog). Expect further tightening of the legacy flag in future releases.

**Protected paths that always prompt even in bypass** (by design, not a bug):
- Directories: `.git`, `.vscode`, `.idea`, `.husky`
- Files: `.gitconfig`, `.gitmodules`, `.bashrc`, `.bash_profile`, `.zshrc`, `.zprofile`, `.profile`, `.ripgreprc`, `.mcp.json`, `.claude.json`

Layer 3 (the PermissionRequest hook) catches these too, so in practice Tyler's sessions see zero prompts.

---

## What NOT to do

- **Never set `permissions.disableBypassPermissionsMode: "disable"`** in any scope. A stray `"disable"` in any settings file locks bypass off system-wide.
- **Never put `defaultMode` at the top level** of `settings.json` — it belongs inside `permissions`.
- **Never put `skipDangerousModePermissionPrompt` inside `permissions`** — it's top-level. The docs' formatting suggests otherwise but the field is top-level.
- **Never use `dontAsk` or `auto` mode** as alternatives. `dontAsk` is broken for Edit/Write on Windows 2.1.86+ and auto-denies unlisted tools anyway. `auto` runs actions through a classifier that can still block and prompt after N blocks — not "zero prompts."
- **Never rely on a project-level `.claude/settings.json` to override a user-level default to something MORE restrictive.** Project scope wins over user scope per precedence rules, and silently downgrading bypass has caused exactly the symptom Tyler reported. If a project needs restrictions, use `deny` rules, not a different `defaultMode`.
- **Never run Claude Code against repos on SMB/NFS/UNC paths.** The OS trust layer silently disables bypass, and the banner still reads "Bypass permissions mode" — hard to diagnose.
- **Never commit `settings.local.json`.** It's gitignored for a reason (personal scope overrides).

---

## Verification

To verify the policy is active in any session, run:

```bash
alias claude     # should show: claude --dangerously-skip-permissions
cat ~/.claude/settings.json | python3 -c "import sys,json; d=json.load(sys.stdin); print('defaultMode:', d['permissions']['defaultMode']); print('PermissionRequest hook:', 'PermissionRequest' in d.get('hooks',{}))"
```

Expected output:
```
alias claude='claude --dangerously-skip-permissions'
defaultMode: bypassPermissions
PermissionRequest hook: True
```

To audit across all project repos:

```bash
/1000xagent:audit-permissions
```

---

## When to Revisit This Policy

- **Anthropic ships a fix for #34923 or #40241** — Layer 1 or Layer 3 become redundant. Don't remove them eagerly; let them sit as defense-in-depth until the fix is proven across versions.
- **Tyler's threat model changes** — e.g. if he starts running Claude Code against untrusted third-party repos, or adds network-mounted storage, or deploys Claude Code in a multi-user environment. The "isolated environment" assumption must still hold.
- **Claude Code releases a new permission mode** — e.g. a "trusted bypass" mode with prompt-injection protection. Migrate if it's strictly better than layered bypass.
- **Any settings.json edit accidentally removes `permissions.defaultMode` or the PermissionRequest hook** — run `/1000xagent:audit-permissions` to detect drift.
