diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 4eb981e..312e5b4 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -27,6 +27,7 @@ rules: | BDR-003 | 2026-04-23 | Gitignore wildcard + negations pattern for .claude/ | accepted | | BDR-004 | 2026-04-27 | Adopt auto permission mode as default | accepted | | BDR-005 | 2026-04-27 | `motion` as default animation library; advisor stays read-only | accepted | +| BDR-006 | 2026-05-03 | Caveman as 4th always-on plugin (output compression) | accepted | --- @@ -95,3 +96,19 @@ rules: - `eligible|motion-v`: Vue 3, Nuxt - `no|-`: backend, CLI, embedded, Flutter, static HTML, **React Native** (use `react-native-reanimated`), Astro without UI integration, no `package.json` - **Reference**: helper at `lib/animation-lib-check.sh`; integration in `skills/init-project/SKILL.md` STEP 5e, `skills/onboard/SKILL.md` STEP 2.5, `agents/plugin-advisor.md` PHASE 1/2/3, `lib/design-gate.md`. + +## BDR-006 — Caveman as 4th always-on plugin (output compression) + +- **Date**: 2026-05-03 +- **Status**: accepted +- **Decision**: install `JuliusBrussee/caveman` in the always-on tier alongside `security-guidance`, `superpowers`, and `rtk`. "Full" install = plugin (`/caveman` + cavecrew agents + plugin-scoped SessionStart/UserPromptSubmit hooks) + standalone hooks (statusline + stats badge in `~/.claude/hooks/`) + `caveman-shrink` MCP scaffold (NOT auto-registered — proxy needs upstream wrapper). `install-plugins.sh` STEP 5.5 calls `enable_plugin "caveman" "caveman"` to write it into `enabledPlugins`. Hook paths in `settings.json` are normalized to `~/.claude/hooks/...` post-install so this user's home dir doesn't leak across machines. +- **Why**: caveman compresses Claude's output ~75% via caveman-speak while preserving technical substance. Symmetrical with rtk (input compression hook) — rtk shrinks tool I/O, caveman shrinks model output. Both hooks pay zero passive cost in a clean session and amortize across long runs. Always-on is justified: the plugin auto-deactivates with phrases like "stop caveman" / "normal mode", so toggle would be friction without benefit. +- **Alternatives rejected**: + - Toggle plugin (start OFF) — rejected: misses the by-default benefit; the user would need to remember `claude plugin enable caveman@caveman` per session, which negates the auto-compression value. + - `--minimal` install (plugin only) — rejected: loses the standalone stats badge that surfaces token-saving telemetry. + - `--all` install (adds per-repo `caveman-rules.md` etc. into `$PWD`) — rejected: would litter THIS config repo (the cwd at install time) with rule files meant for project repos. Let users opt in per-repo when they want it. + - Auto-register `caveman-shrink` MCP — rejected: the proxy errors with "missing upstream command" without an upstream MCP to wrap, fails health checks. Print a snippet instead and let the user pick which upstream they want compressed (filesystem, github, …). +- **Caveats**: + - Caveman's `hooks/install.sh` writes absolute paths (`$HOME/.claude/hooks/caveman-*.js`) into `settings.json`. Since `settings.json` is symlinked into the repo, the absolute path would commit a username. STEP 5.5 runs a Python post-process to rewrite to portable `~/.claude/hooks/...` form (bash expands `~` before passing to `node`). + - Caveman's hook files materialize in `hooks/` (the repo dir, not `~/.claude/hooks/`) because the latter is a symlink. They're added to `.gitignore` to prevent accidental commit of user-scope state. +- **Reference**: install-plugins.sh STEP 5.5, lib/detect-plugins.sh `detect_caveman*` + `plugin_enabled`, doctor.sh caveman block, commit `9b20b84`. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index 44d037e..b2f4d29 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -28,3 +28,10 @@ rules: - Learning: Claude Code `disable*` settings use the sentinel string `"disable"`, not a boolean (LRN-003). - 3 atomic commits (`f7f033f..1421578`) via `/commit-change`. - Animation lib autoflow added: new helper `lib/animation-lib-check.sh` + STEP 5e in `/init-project` (auto-install) + STEP 2.5 in `/onboard` (opt-in) + read-only detection in `plugin-advisor` PHASE 1/2/3 + signal in `lib/design-gate.md` + scaffolder note. `motion` chosen over legacy `framer-motion` (BDR-005, LRN-004). + +## 2026-05-03 + +- Added `JuliusBrussee/caveman` as 4th always-on plugin (BDR-006). Full install: plugin + standalone hooks + caveman-shrink MCP scaffold (snippet only, not auto-registered — proxy needs upstream wrapper, LRN-006). +- Discovered two co-masking bugs: `claude plugin install` doesn't enable (LRN-005) and `session-start.sh` was hardcoding "✅ ON: security-guidance rtk superpowers" regardless of actual state. Added `enable_plugin()` helper + `plugin_enabled()` detector reading `enabledPlugins` from `settings.json`. Banner now reflects reality. +- Side fix: doctor.sh exited under `set -euo pipefail` when gstack/skills/ was missing — wrapped find in brace + `|| true`. +- 3 atomic commits (`0184818..2ec7935`). diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 5a81fc3..87bc7cc 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -24,6 +24,8 @@ rules: | 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 | | LRN-004 | 2026-04-27 | `framer-motion` was rebranded `motion` in Nov 2024 — different packages per framework | any new project recommending an animation lib; auditing legacy imports | +| LRN-005 | 2026-05-03 | `claude plugin install` does NOT enable — separate `claude plugin enable` required | every plugin installer that targets ALWAYS-ON status | +| LRN-006 | 2026-05-03 | `caveman-shrink` (and any MCP middleware proxy) is non-functional without an upstream wrapper | any MCP middleware/proxy package — never `claude mcp add` it bare | --- @@ -67,3 +69,29 @@ rules: - When auditing existing projects, check both `framer-motion` and `motion` keys in `package.json` deps; treat either as "animation already covered". - Before adopting any "industry default" lib in a framework, verify the canonical package name is current — naming churn (rebrand, scope change `@org/lib`, fork) is common in JS land. - **Reference**: helper `lib/animation-lib-check.sh`, BDR-005. + +## LRN-005 — `claude plugin install` does NOT enable — `claude plugin enable` is a separate step + +- **Date**: 2026-05-03 +- **Pattern**: the Claude Code CLI splits "available" from "active" for marketplace plugins. `claude plugin install --scope user name@source` only copies the plugin into `~/.claude/plugins/cache////`. It does NOT write `name@source: true` into the user's `settings.json:enabledPlugins` map. Without an explicit `claude plugin enable name@source`, the plugin sits dormant — installed but unloaded. This is symmetric with `claude plugin disable`, which keeps the cache and only removes the enabledPlugins entry. +- **Context**: discovered while auditing why `security-guidance` and `superpowers` were ✘ disabled in `claude plugin list` despite the project's `install-plugins.sh` summary banner declaring them "ALWAYS ON". Root cause: `install_plugin()` only ran `claude plugin install`, never `enable`. The bug had stayed invisible because a hardcoded `printf "│ ✅ ON : security-guidance rtk superpowers │"` in `session-start.sh` printed the same names regardless of actual state — the lying banner agreed with the lying install. +- **Future application**: + - For any plugin meant to be ALWAYS ON, follow `claude plugin install` with `claude plugin enable name@source` (idempotent — no-op if already enabled). + - Detect "actually enabled" via `enabledPlugins[name@source] === true` in `settings.json`, NOT by the presence of the cache dir. The pattern is implemented in `lib/detect-plugins.sh:plugin_enabled()` (filesystem grep, no subprocess). + - Any banner / status display that claims a plugin is on must read state, never hardcode names. Hardcoded labels turn a single bug into two co-conspiring bugs that mask each other. +- **Reference**: commit `2ec7935`, `lib/detect-plugins.sh:plugin_enabled`, `install-plugins.sh:enable_plugin()`. + +## LRN-006 — `caveman-shrink` (and any MCP middleware proxy) needs an upstream wrapper to function + +- **Date**: 2026-05-03 +- **Pattern**: some MCP packages are middleware proxies, not standalone servers. They wrap an upstream MCP server and transform its responses (e.g. `caveman-shrink` compresses prose fields). Running them bare via `claude mcp add proxy-name -- npx -y proxy-pkg` registers a server that errors immediately with "missing upstream command" — every health check fails, and Claude Code reports the MCP as broken until a human intervenes. The CLI `claude mcp add` doesn't validate that the configured command launches a working stdio MCP, so the bad registration silently lands. +- **Context**: when adding caveman, the upstream installer auto-registers `claude mcp add caveman-shrink -- npx -y caveman-shrink` and prints "registered. wrap an upstream by editing the mcpServers entry". Following that flow leaves the user with a permanently failing MCP entry until they realize they have to edit `~/.claude.json` manually. +- **Future application**: + - For any MCP that is a proxy/middleware (read package docs for "upstream", "wraps", "proxy"), register it under a DERIVED name `-` with the upstream baked into the args. Example for caveman-shrink wrapping the filesystem server: + ``` + claude mcp add caveman-shrink-fs --scope user -- \ + npx -y caveman-shrink npx -y @modelcontextprotocol/server-filesystem /path + ``` + - Detection of "is this MCP correctly set up?" must look for the derived name (`caveman-shrink-*`), not the bare proxy name. Bare-name registration is treated as broken. + - Default install scripts should NOT auto-register middleware MCPs — print the snippet for the user to choose an upstream. See `install-plugins.sh` STEP 5.5. +- **Reference**: commit `9b20b84`, `lib/detect-plugins.sh:detect_caveman_shrink`, `install-plugins.sh` STEP 5.5 MCP block.