diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 963307f..ea24ea1 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -25,6 +25,7 @@ rules: | BDR-001 | 2026-04-22 | Uniform --help helper via session-start hook (option C) | accepted | | BDR-002 | 2026-04-23 | Move tasks/ + introduce memory + audits under .claude/ | accepted | | BDR-003 | 2026-04-23 | Gitignore wildcard + negations pattern for .claude/ | accepted | +| BDR-004 | 2026-04-27 | Adopt auto permission mode as default | accepted | --- @@ -62,3 +63,17 @@ rules: - Drop `.claude/` from gitignore entirely — rejected: `.claude/settings.local.json` and `.claude/agent-memory/` must stay ignored (per-machine). - Track paths via `.gitattributes` or an external tool — rejected: over-engineering, git handles this natively. - **Reference**: commit `499cd07`, `git check-ignore -v` verified on 4 paths (2 tracked, 2 ignored). + +## BDR-004 — Adopt auto permission mode as default + +- **Date**: 2026-04-27 +- **Status**: accepted +- **Decision**: set `permissions.defaultMode` to `"auto"` in user-scope `settings.json` and drop `disableAutoMode: "disable"`. Auto mode runs a classifier on every action and blocks risky operations (`curl|bash`, prod deploys, force push, IAM grants, mass deletes, exfiltration to external endpoints) while auto-approving local edits, lockfile-declared dep installs, and read-only HTTP. +- **Why**: prompt fatigue under `default` mode is significant on multi-step autonomous work. Auto mode keeps a safety net (classifier review) without the per-tool friction. The classifier also re-evaluates conversation-stated boundaries ("don't push", "wait for review") on every check, so verbal constraints carry weight. +- **Alternatives rejected**: + - Keep `default` — too many prompts, breaks flow on long tasks. + - `acceptEdits` — eliminates prompts but no classifier, blanket trust on Bash beyond filesystem helpers. + - `bypassPermissions` — skips all checks, no prompt-injection guard. Only for isolated containers. + - `dontAsk` — full denylist, breaks anything not pre-approved. Suited to CI, not interactive work. +- **Caveats**: requires Claude Code v2.1.83+, plan ≠ Pro (Max/Team/Enterprise/API only), Sonnet 4.6 / Opus 4.6 / Opus 4.7, Anthropic API provider. On entering auto mode, blanket allow rules (`Bash(*)`, `Bash(python*)`, package-manager run, `Agent`) are dropped and restored on exit. +- **Reference**: commit `1421578`. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 359f625..5936f00 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -21,3 +21,9 @@ rules: - 9 atomic commits (`c721a36..a9606aa`) via `/commit-change` — first real execution of Phase 4 CAPITALIZE. - Decisions logged: BDR-002, BDR-003. Learnings: LRN-002. Blockers: BLK-002. - English-only rule enforced in all CAPITALIZE specs (commit `bfcca72`); 9 existing entries retrofitted to English in follow-up commit. + +## 2026-04-27 + +- Settings: switched `permissions.defaultMode` from `"default"` to `"auto"` and dropped `disableAutoMode: "disable"` (BDR-004); reorganised top-level keys and added `effortLevel: "xhigh"`; removed stale root `TODO.md` (already migrated to `.claude/tasks/TODO.md`). +- Learning: Claude Code `disable*` settings use the sentinel string `"disable"`, not a boolean (LRN-003). +- 3 atomic commits (`f7f033f..1421578`) via `/commit-change`. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index ac5a35e..c0af381 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -22,6 +22,7 @@ rules: |----|------|---------|------------| | LRN-001 | 2026-04-22 | `rtk` shape-compression breaks pipes | any pipeline chaining `rtk curl/cat/read` into `jq`, `python -c`, `awk` | | LRN-002 | 2026-04-23 | Moving report-file paths requires grepping bash READS, not just WRITES | any refactor that moves a generated file used by a dispatcher | +| LRN-003 | 2026-04-27 | Claude Code `disable*` settings use sentinel string `"disable"`, not boolean | any change to `permissions.defaultMode` or related blocker keys | --- @@ -41,3 +42,14 @@ rules: - Before declaring a file-path migration "complete", grep the **basename** (`grep -rn "HARDEN\.md"`) in addition to the full path — to catch bare bash usages. - If the file is used in pipelines (`test`, `grep`, `wc`, `cat`, `head`), search for those verbs explicitly. - **Verify-gates save work**: one extra round asked by the user forced exhaustive re-grepping. Without it, two dispatchers would have shipped broken. + +## LRN-003 — Claude Code `disable*` settings use the sentinel string `"disable"`, not a boolean + +- **Date**: 2026-04-27 +- **Pattern**: Claude Code blocker-style settings (`disableAutoMode`, `disableBypassPermissionsMode`) use the literal string `"disable"` as a sentinel. The key being absent means the feature is available; the value `"disable"` is what turns the blocker on. Any other value (including `false`, `true`, `null`) has no effect — the doc explicitly states this. +- **Context**: switching `permissions.defaultMode` to `"auto"` while `disableAutoMode: "disable"` was still present would have failed at startup ("auto mode unavailable"). The naming `disable: "disable"` reads ambiguously — easy to assume it's a boolean toggle and leave the key in place. +- **Future application**: + - Before changing `defaultMode`, audit the matching `disable*` key in the same `permissions` block. If present with value `"disable"`, remove it. + - Same logic for `bypassPermissions` mode and `disableBypassPermissionsMode`. + - Don't trust the doc's naming — read the value semantics. Sentinel strings beat booleans here because the harness can distinguish "unset" from "explicitly off" (admin policy). +- **Reference**: commit `1421578`, doc `https://code.claude.com/docs/en/settings`.