type: learnings_registry entry_prefix: LRN schema: id: LRN-XXX date: YYYY-MM-DD pattern: string (what was observed, abstracted) context: string (where/when it happened - concrete) future_application: string (when to recall this) rules:
| ID | Date | Pattern | Applies to |
|---|---|---|---|
| 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 |
| LRN-004 | 2026-04-27 | framer-motion rebranded motion Nov 2024 — different packages per framework |
any new project recommending animation lib; auditing legacy imports |
| LRN-005 | 2026-05-03 | claude plugin install does NOT enable — separate claude plugin enable required |
every plugin installer targeting ALWAYS-ON status |
| LRN-006 | 2026-05-03 | caveman-shrink (and any MCP middleware proxy) non-functional without upstream wrapper |
any MCP middleware/proxy package — never claude mcp add it bare |
| LRN-007 | 2026-05-06 | toggle-external.sh enable missed source-only state (3rd lifecycle case) |
toggle scripts for tools with separate install + symlink steps |
| LRN-008 | 2026-05-06 | Biggest skill-quality wins from edge-case tables, not workflow rewrites | any skill <85 — first check for FAILURE PATHS / EDGE CASES / ERROR HANDLING section |
| LRN-009 | 2026-05-06 | Dry-run scoring noise wrongly triggers reverts on already-strong skills | darwin-skill ratchet on skills >91 — relax or use real subagent eval |
| LRN-010 | 2026-05-06 | ~/.claude/skills,agents symlink to Documents/claude — git from ~/.claude fails |
any optimization or batch edit on personal skills/agents |
rtk shape-compression silently breaks downstream parsersrtk) intercepts stdout and returns schematized/compressed representation instead of raw payload, every downstream parser breaks silently — user (or LLM) never sees rtk's output, only parser error.rtk curl replaces raw JSON output with tokenized version, regardless of TTY vs pipe. Claude Code hooks auto-rewrite curl → rtk curl, so behavior impossible to anticipate without knowing hook.exclude_commands=["curl"] in ~/.config/rtk/config.toml, or rtk proxy. See BLK-001.test -s X.md, grep ... X.md, wc -l X.md — refs invisible if only grep for "write" or "output path"..claude/audits/ refactor (commit 5c5e82c). First pass: updated write paths across 5 skills (seo/geo/harden/validate/code-clean) and 3 agents. User asked for verify-gate. They re-grepped, found 10+ bare bash refs (e.g. test -s HARDEN.md, grep -oE ... VALIDATE.md) missed — dispatchers broken (looking at project root while agent writing to .claude/audits/). Fixed in commit 5c5e82c (bundled with same commit).grep -rn "HARDEN\.md") plus full path — catch bare bash usages.test, grep, wc, cat, head), search for those verbs explicitly.disable* settings use sentinel string "disable", not booleandisableAutoMode, disableBypassPermissionsMode) use literal string "disable" as sentinel. Key absent = feature available; value "disable" turns blocker on. Any other value (including false, true, null) has no effect — doc explicitly states this.permissions.defaultMode to "auto" while disableAutoMode: "disable" still present would have failed at startup ("auto mode unavailable"). Naming disable<Foo>: "disable" reads ambiguously — easy to assume boolean toggle and leave key in place.defaultMode, audit matching disable* key in same permissions block. If present with value "disable", remove it.bypassPermissions mode and disableBypassPermissionsMode.1421578, doc https://code.claude.com/docs/en/settings.framer-motion rebranded motion (Nov 2024) — different packages per frameworkframer-motion renamed motion November 2024. Rename not cosmetic: bundles React (motion/react), Svelte, vanilla-JS support under single npm package, while Vue gets own parallel package motion-v. Legacy package framer-motion still installs and works but in maintenance mode — recommending it in new framework default locks projects into legacy import paths day one. Detection of "is animation already covered" must include both names plus broader anim ecosystem (gsap, lottie-react, react-spring, popmotion, @formkit/auto-animate) to avoid double-installs./init-project and /onboard. Initial user phrasing "framer-motion" (old name remembered). Picking package name without verifying rename would have shipped legacy imports in every new scaffold.motion (import { motion } from 'motion/react').motion-v (separate package, separate API).motion — use react-native-reanimated (motion targets DOM).framer-motion and motion keys in package.json deps; treat either as "animation already covered".@org/lib, fork) common in JS land.lib/animation-lib-check.sh, BDR-005.claude plugin install does NOT enable — claude plugin enable separate stepclaude plugin install --scope user name@source only copies plugin into ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/. Does NOT write name@source: true into user's settings.json:enabledPlugins map. Without explicit claude plugin enable name@source, plugin sits dormant — installed but unloaded. Symmetric with claude plugin disable, which keeps cache and only removes enabledPlugins entry.security-guidance and superpowers were ✘ disabled in claude plugin list despite project's install-plugins.sh summary banner declaring them "ALWAYS ON". Root cause: install_plugin() only ran claude plugin install, never enable. Bug stayed invisible because hardcoded printf "│ ✅ ON : security-guidance rtk superpowers │" in session-start.sh printed same names regardless of actual state — lying banner agreed with lying install.claude plugin install with claude plugin enable name@source (idempotent — no-op if already enabled).enabledPlugins[name@source] === true in settings.json, NOT presence of cache dir. Pattern implemented in lib/detect-plugins.sh:plugin_enabled() (filesystem grep, no subprocess).2ec7935, lib/detect-plugins.sh:plugin_enabled, install-plugins.sh:enable_plugin().caveman-shrink (and any MCP middleware proxy) needs upstream wrapper to functioncaveman-shrink compresses prose fields). Running them bare via claude mcp add proxy-name -- npx -y proxy-pkg registers server that errors immediately with "missing upstream command" — every health check fails, and Claude Code reports MCP broken until human intervenes. CLI claude mcp add doesn't validate that configured command launches working stdio MCP, so bad registration silently lands.claude mcp add caveman-shrink -- npx -y caveman-shrink and prints "registered. wrap an upstream by editing the mcpServers entry". Following that flow leaves user with permanently failing MCP entry until they realize they must edit ~/.claude.json manually.Future application:
For any MCP that is proxy/middleware (read package docs for "upstream", "wraps", "proxy"), register under DERIVED name <proxy>-<upstream> with upstream baked into args. Example for caveman-shrink wrapping 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.
toggle-external.sh enable missed source-only statelib/toggle-external.sh enable <tool> for npx/external skills (darwin-skill, find-skills, emil-design-eng) handled 2 states only: symlink in skills-disabled/ → move to skills/, or symlink in skills/ → already enabled. Missed 3rd: source dir at ~/.agents/skills/<tool> but no symlink. First-run after make plugin lands here until bash link.sh runs. enable errored not installed — run: make plugin — misleading, plugin already installed../lib/toggle-external.sh enable darwin-skill after fresh install. ~/.agents/skills/darwin-skill/ populated by install-plugins.sh STEP 8.5 npx call, but link.sh (separate step) not run, so skills/darwin-skill symlink never created. Fix lib/toggle-external.sh:161-179 — add elif [ -d "$src" ] branch creating symlink direct when source dir present. Error message now show resolved source path.enable/disable) both handle same lifecycle states; missing state in one half = silent dead end.lib/toggle-external.sh:161-179, link.sh:69-83, install-plugins.sh:598-633 STEP 8.5.| situation | action | shape moved D3 from 3-7 → 9-10 and total +5 to +18.target not found, input malformed, tool/API timeout, user denies action, partial output, permission denied. Map each → fallback / retry / ask-user / fail-fast..claude/audits/DARWIN-SKILL-OPTIMIZATION.md, commits 649351b, eb34627, 1768d04, ef87074, a3f28d5.~/.claude/notes/) so work not lost — second smaller patch can reintroduce idea..claude/audits/DARWIN-SKILL-OPTIMIZATION.md, commits 63e08f9→822d437 revert (code-clean), c7b8522→765d1c1 revert (doc).~/.claude/skills/<x>/SKILL.md or ~/.claude/agents/<x>.md modifies file at /home/bchanot-ubuntu/Documents/claude/{skills,agents}/. ~/.claude is empty config dir with symlinks; actual git repo + working tree is in Documents/claude. git add from ~/.claude fails with pathspec is beyond a symbolic link. Must operate git from Documents/claude.~/.claude first (separate git repo, mostly empty). Real branch with skill changes had to be created in Documents/claude. Two repos, two branches./home/bchanot-ubuntu/Documents/claude for git to track changes.readlink ~/.claude/skills + readlink ~/.claude/agents first if unsure. Both point to Documents/claude/{skills,agents}.~/.claude — nothing to track for skill content..claude/audits/DARWIN-SKILL-OPTIMIZATION.md, branch auto-optimize/skills-20260506-1730 in Documents/claude.