diff options
Diffstat (limited to 'todo.org')
| -rw-r--r-- | todo.org | 83 |
1 files changed, 83 insertions, 0 deletions
@@ -1528,3 +1528,86 @@ removed links if needed (the install loop is idempotent). accidental select-all). - =--source= flag that also runs =git rm= against the rulesets source for the selected item. Probably bad idea — too easy to lose work. +- The =bridge → $(SKILLS_DIR)/claude-rules= entry above is stale — the + bridge symlink got removed in a later commit. Drop that bullet when the + recipe lands. + +* DONE [#A] Add =make doctor= — verify ~/.claude/ matches repo + settings.json :feature: + +A drift detector that scans =~/.claude/= and reports anything inconsistent with what the repo expects. Single-command answer to "is my machine consistent with rulesets?" + +** Why this matters + +A 2026-05-06 sweep found =~/.claude/hooks/= didn't exist on this machine even though =settings.json= referenced =~/.claude/hooks/precompact-priorities.sh= as a PreCompact hook. Compaction would have silently failed to invoke the hook. The fix was =make install-hooks=, but the breakage was invisible until I happened to grep for it. =make doctor= run regularly (or even as part of session start) would catch this kind of drift in seconds instead of after the fact. + +** Checks + +- Every entry in =settings.json= ="hooks"= block points at a file that exists. +- Every entry in =enabledPlugins= has a matching install under =~/.claude/plugins/data/=. +- Every skill in =$(SKILLS)= has a working symlink at =~/.claude/skills/<name>=. +- Every rule in =$(RULES)= has a working symlink at =~/.claude/rules/<name>=. +- Every default hook has a symlink at =~/.claude/hooks/<name>= (warn-only — opt-out is legitimate). +- =settings.json= and =.mcp.json= symlinks resolve to the rulesets versions. +- =mcp/install.py= state matches =claude mcp list= (every server in =servers.json= is registered). +- No dangling symlinks anywhere under =~/.claude/=. + +** Output + +One line per check: =ok= / =WARN= / =FAIL=. Final summary: =N ok, M warnings, K failures=. Exit non-zero on any failure so it can ride a pre-flight check. + +* TODO [#B] Document the =mcp/= install pipeline in =mcp/README.org= + +=mcp/= has =install.py=, =servers.json=, =secrets.env.gpg=, =gcp-oauth.keys.json= (gitignored, regenerated at install). No README. Coming back to this in three months I'll re-discover how the bundle is structured, what =install.py= does, and how to rotate tokens. Saving that re-discovery is the whole point. + +** What to cover + +- Layout: what each file is, which are tracked vs gitignored. +- Secrets bundle shape: how vars are listed in =secrets.env=, the symmetric-encryption pattern (=gpg -c --cipher-algo AES256=), the base64-bundled OAuth artifacts (=GCP_OAUTH_KEYS_JSON_B64=, =GOOGLE_DOCS_PERSONAL_TOKEN_B64=, =GOOGLE_DOCS_WORK_TOKEN_B64=). +- Install flow: =make install-mcp= → =install.py= decrypts, writes the keys file and Google Docs token caches at mode 600, expands =${VAR}= in =servers.json=, calls =claude mcp add --scope user= for unregistered servers. Idempotent. +- Token rotation: when a refresh token gets revoked, the recovery flow (re-auth on one machine, re-bundle, recommit). +- Adding a new server: edit =servers.json=, add any new =${VAR}= placeholders to the bundle, re-encrypt. +- The OAuth dance for HTTP-transport servers (linear, notion) versus stdio (google-docs-*) — different paths, different gotchas. + +* TODO [#C] Add =make uninstall-mcp= + =mcp/install.py --check= for symmetry + +Currently the MCP install pipeline only flows one direction. No way to remove rulesets-managed MCP servers in one command. No way to ask "what's the drift between =servers.json= and =claude mcp list=" without eyeballing. + +** =make uninstall-mcp= + +Iterate over =servers.json=, run =claude mcp remove <name> -s user= for each. Ignore "not registered" errors. Idempotent. + +** =mcp/install.py --check= + +Dry-run mode. Decrypt secrets, but instead of registering, print the drift report: + +- Servers in =servers.json= not in =claude mcp list= → =MISSING= +- Servers in =claude mcp list= not in =servers.json= → =EXTRA= +- Servers in both → =ok= + +Useful for diagnosing connection failures and for the eventual =make doctor= integration. + +* TODO [#C] Update =README.org= with MCP install pipeline section + +=README.org= covers global install, per-project language bundles, and design principles, but doesn't mention =make install-mcp= or the =mcp/= directory. Add a short section after "Per-project language bundles" describing the user-scope MCP install pattern (decrypt → expand → register) and pointing at the eventual =mcp/README.org=. + +* TODO [#C] Token-rotation helper for =@a-bonus/google-docs-mcp= OAuth refresh + +When a Google refresh token gets revoked (re-grant scopes, removed Connected App, account password reset), recovery is currently manual: run =npx -y @a-bonus/google-docs-mcp= with the right env, follow the URL in a browser, kill the process, base64-encode the new =token.json=, decrypt =secrets.env.gpg=, replace the var, re-encrypt. A small =mcp/refresh-google-docs-token.sh <profile>= would chain that into one command. + +** Sketch + +#+begin_src bash +# usage: mcp/refresh-google-docs-token.sh personal +profile="$1" +gpg -d ... | grep -v "GOOGLE_DOCS_${profile^^}_TOKEN_B64" > /tmp/secrets.env.tmp +GOOGLE_MCP_PROFILE="$profile" npx -y @a-bonus/google-docs-mcp & +xdg-open <captured-url> +# wait for ~/.config/google-docs-mcp/$profile/token.json to land +kill %1 +echo "GOOGLE_DOCS_${profile^^}_TOKEN_B64=$(base64 -w0 ~/.config/google-docs-mcp/$profile/token.json)" >> /tmp/secrets.env.tmp +gpg -c --cipher-algo AES256 -o mcp/secrets.env.gpg.new /tmp/secrets.env.tmp +mv mcp/secrets.env.gpg.new mcp/secrets.env.gpg +rm /tmp/secrets.env.tmp +#+end_src + +The flow tonight worked but took a handful of manual steps. One script collapses it. |
