Skip to content

plugins: replace enable-first profiles with a native all-true manifest - #58

Draft
yulonglin wants to merge 2 commits into
mainfrom
worktree-plugin-overhaul
Draft

plugins: replace enable-first profiles with a native all-true manifest#58
yulonglin wants to merge 2 commits into
mainfrom
worktree-plugin-overhaul

Conversation

@yulonglin

@yulonglin yulonglin commented Aug 2, 2026

Copy link
Copy Markdown
Owner

What

Replaces the enable-first claude-tools context plugin system with the platform-native model: a single user-scope install manifest, and no per-project plugin state.

Previously every repo needed a .claude/context.yaml before its plugins worked, and claude-tools context wrote project-scope true/false maps for all 33 installed plugins — the source of the "project settings override your user setting" warnings in /plugin.

Now enabledPlugins in claude/settings.json lists the 24 kept plugins with an explicit true. An explicit true wins at every scope, so the setup does not rely on the platform's undocumented no-entry default.

Changes

  • Removed SessionStart hooks context_auto_apply.sh and check_things_mcp.sh
  • deploy.sh: dropped the claude-tools context --sync step (marketplaces were already declared natively in extraKnownMarketplaces, so it was redundant) and the context-templates deploy block
  • Deleted .claude/context.yaml and claude/templates/contexts/profiles.yaml
  • statusline.sh: removed the now-dead context.yaml reader
  • extraKnownMarketplaces 7 → 6: dropped dev-browser-marketplace; kept productivity-tools, which still ships the macOS-only bear-mcp
  • Pruned 9 unused plugins: dev-browser, figma, gopls-lsp, huggingface-skills, imessage, plugin-dev, ralph-loop, swift-lsp, things-mcp
  • Rewrote claude/docs/plugin-management.md; fixed the CLAUDE.md reference, which pointed at a path that did not resolve

Also done outside the repo (live runtime): the 9 uninstalls, deregistering rust-skills and dev-browser-marketplace, and trashing 9 temp_git_* cache dirs.

Findings worth reading

  • Every plugin on this machine was installed at project scope, bound to the unrelated quiet-hooks worktree via projectPath. Install records pinned to a worktree die with it. Plugins should be installed at user scope; claude plugin list shows the Scope column.
  • claude plugin uninstall resolves scope to the owning project, not the CWD — run from this worktree with the default --scope user, it edited quiet-hooks/.claude/settings.json. It also leaves install records behind, so "uninstalled" ≠ "absent from installed_plugins.json".
  • The "no entry means enabled" premise is unverified. defaultEnabled is absent for all 276 official plugins, and every installed plugin already carries an explicit entry, so there was no clean case to observe. This is the strongest argument for the all-true manifest over an empty map.
  • Open risk: deploy.sh runs no installs, and it is unconfirmed whether a user-scope true entry installs a missing plugin or only enables a present one. Treat the cross-machine claim as unproven until a second machine deploys.

Verification

  • statusLine/hooks/permissions gate passes on claude/settings.json (per .claude/rules/dotfiles-settings.md); 24 entries, all true
  • zsh -n deploy.sh and bash -n claude/statusline.sh pass
  • Runtime marketplaces now exactly match extraKnownMarketplaces (6)
  • Not yet verified: the /plugin warning/error count, which needs a fresh session

https://claude.ai/code/session_01WoJYQoyUNVUn56h87MHDQ7


Status, split three ways (updated after the follow-up sweep, 9588dbc)

1. Landed in the repo — verified. The all-true 24-entry manifest, hook removals, marketplace list 7 -> 6, deploy.sh and statusline.sh cleanup, docs rewrite. Plus 9588dbc, which swept seven stale references the first pass missed: a CLAUDE.md row and a README section documenting the retired CLI, an edit-profiles alias opening a deleted file, a claude-plugin-reset step calling a nonexistent claude-context binary, and two orphaned hook scripts. stale-claims.sh now asserts the manifest is all-true instead of running a permanently-skipped profiles check.

2. Changed in the live runtime, outside the repo. 9 plugins uninstalled; rust-skills and dev-browser-marketplace deregistered; temp_git_* cache dirs trashed. None of this is captured by the diff — a fresh machine gets the repo state, not this.

3. Changed in another worktree — unintended. Running claude plugin uninstall resolved scope to the owning project, which was the live quiet-hooks worktree, not the CWD. Net uncommitted delta there is one line: dev-browser@dev-browser-marketplace: false removed. Low harm (that plugin is uninstalled and its marketplace deregistered), and I deliberately did not touch the file again — it belongs to a running session.

Acceptance criteria that do NOT pass

  • "Every pruned plugin is absent from installed_plugins.json" — fails. All 9 records persist; claude plugin uninstall edits enabledPlugins but leaves the install record. Not satisfiable by the CLI alone.
  • "/plugin reports zero override warnings and zero hard errors" — unverified; needs a fresh session to observe.
  • "No file references claude-tools context" — passed only after 9588dbc. It did not pass at f89b1f4.

Pre-existing, not caused by this PR

quiet-hooks/.claude/settings.json carries 32 entries with 10 set false, including telegram, playwright, research and writing. Project scope beats the user-scope true manifest, so those stay off in that worktree. It dies with the worktree, so no action taken.

Recommended follow-up

Every plugin on this machine is recorded as "scope": "project" bound to quiet-hooks — install records pinned to a worktree die with it. Reinstall the 24 at --scope user once no session is using that worktree.

claude-tools context required a .claude/context.yaml in every repo before
its plugins worked, and wrote project-scope true/false maps for all 33
installed plugins - the source of the 'project settings override your
user setting' warnings in /plugin.

Replace it with a user-scope install manifest: enabledPlugins in
claude/settings.json lists the 24 kept plugins with an explicit true,
and no project-scope plugin state is generated at all. An explicit true
wins at every scope, so this does not depend on the platform's
undocumented no-entry default.

- drop SessionStart hooks context_auto_apply.sh and check_things_mcp.sh
- deploy.sh: drop the claude-tools context --sync step (marketplaces are
  already declared natively in extraKnownMarketplaces) and the
  context-templates deploy block
- delete .claude/context.yaml and claude/templates/contexts/profiles.yaml
- statusline.sh: drop the now-dead context.yaml reader
- extraKnownMarketplaces: 7 -> 6 (drop dev-browser-marketplace;
  productivity-tools stays, it still ships the macOS-only bear-mcp)
- prune 9 unused plugins: dev-browser, figma, gopls-lsp,
  huggingface-skills, imessage, plugin-dev, ralph-loop, swift-lsp,
  things-mcp

Accepted loss: OS-conditional loading (profiles.yaml had a macos:
section). Its only entry, bear-mcp, was not installed anywhere.

Claude-Session: https://claude.ai/code/session_01WoJYQoyUNVUn56h87MHDQ7
…ssed

The manifest change landed in f89b1f4 but left live references to the retired
claude-tools context system behind. Each was a real friction bug, not just
stale prose:

- CLAUDE.md: Common Tasks row pointing at a retired command
- README.md: marketplaces documented as synced from profiles.yaml (they are
  declared in extraKnownMarketplaces); dropped the deregistered
  dev-browser-marketplace row and corrected openai-codex -> codex-plugin-cc
- config/aliases/editors.sh: edit-profiles opened a deleted file
- custom_bins/claude-plugin-reset: step 5 re-applied a context profile via a
  claude-context binary that no longer exists, and its --global path had a
  top-level 'local' that would have errored if ever reached; --global/--force
  existed only to drive it
- claude/hooks/{context_auto_apply,check_things_mcp}.sh: orphaned scripts,
  already dereferenced from settings.json in f89b1f4

scripts/audit/stale-claims.sh: check_context_profiles was permanently skipped
(its yaml is gone). Replaced with check_plugin_manifest, which asserts every
enabledPlugins entry is true - so a stray false gate is caught by the audit
rather than by a confusing missing plugin.

Left deliberately: custom_bins/claude-usage-audit still reads profiles.yaml for
per-profile attribution, but guards with an exists() check and returns empty,
so it degrades cleanly. Reworking its data model was out of scope here.

bash -n / zsh -n pass on all five scripts; stale-claims reports the new check OK.

Claude-Session: https://claude.ai/code/session_01WoJYQoyUNVUn56h87MHDQ7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant