diff --git a/.claude/settings.json b/.claude/settings.json index d89dbbd..a27dda6 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,4 +1,7 @@ { + "env": { + "CAVEMAN_DEFAULT_MODE": "off" + }, "permissions": { "allow": [ "Bash(git status*)", "Bash(git diff*)", "Bash(git log*)", "Bash(git pull*)", diff --git a/docs/changelog-20260723-caveman-optin-guard.md b/docs/changelog-20260723-caveman-optin-guard.md new file mode 100644 index 0000000..b328c98 --- /dev/null +++ b/docs/changelog-20260723-caveman-optin-guard.md @@ -0,0 +1,46 @@ +# Changelog -- 2026-07-23 -- caveman plugin: off-by-default opt-in guard + +Session scope: operator-directed install of the `caveman` Claude Code plugin +(third-party, `JuliusBrussee/caveman`) plus guards so it never auto-arms while +operating the cloud. Harness-config only -- NO cloud mutation, NO script/runbook +change, no status implication (CURRENT-STATE untouched). Kept as an available +tool for future hardened-workflow deployment testing, where terse +gated-approval-only output is wanted; verbose fully-gated output stays the +default for live operations. + +## Item 1 -- caveman plugin installed (user scope), hooks inspected read-only + +- Installed `caveman@caveman` at user scope (`~/.claude/plugins/`, git SHA + `0d95a81`) via `claude plugin marketplace add` + `claude plugin install`, + per operator instruction. Purpose: terse "caveman-mode" output (~65% fewer + output tokens, per its README). +- Both auto-wired hooks read in full before trusting them (this host holds + cloud credentials + reaches juju/MAAS/OpenStack, so a plugin's hooks are a + supply-chain surface): `src/hooks/caveman-activate.js` (SessionStart) and + `src/hooks/caveman-mode-tracker.js` (UserPromptSubmit). Finding: purely + behavioral -- NO network calls, NO credential-file access, NO exfiltration; + the only subprocess spawned is the plugin's own stats script, and only on an + explicit `/caveman-stats`. Default mode is `full` (auto-arms on session + start unless guarded) -- the reason for item 2. +- **Revert:** `claude plugin uninstall caveman@caveman`; remove the + `extraKnownMarketplaces.caveman` + `enabledPlugins."caveman@caveman"` keys + from `~/.claude/settings.json`. + +## Item 2 -- opt-in guard: CAVEMAN_DEFAULT_MODE=off (repo + user scope) + +- Repo `.claude/settings.json`: added an `env` block setting + `CAVEMAN_DEFAULT_MODE=off` -- committed, so the intent is durable/shared for + this operating clone. Effect: `getDefaultMode()` returns `off`, the + SessionStart hook skips activation and clears any stale flag; an explicit + `/caveman lite|full|ultra` still activates on demand. `jq` valid, repo-lint + 0 fail / 1 legacy warn (unchanged). +- User `~/.claude/settings.json`: same `env` entry added so the plugin is + off-by-default in ALL of the operator's repos, not just this one (the plugin + is installed user-wide; its bare default is `full`). This file is OUTSIDE the + repo -- NOT committed here; recorded for provenance only. +- Verified `off` is a valid mode (`VALID_MODES` in the plugin's + `caveman-config.js`), so the guard is honored rather than silently ignored. +- **Revert:** remove the `env.CAVEMAN_DEFAULT_MODE` key from whichever + settings.json (repo revert via `git revert ` for the committed one; hand + edit for the user-level one). With the plugin still installed, removing the + guard restores its `full` auto-arm default.