Skip to content

ISSUE-450: Install plugins per scope and let the Claude CLI own enablement - #452

Merged
bguidolim merged 3 commits into
mainfrom
bruno/ISSUE-450-plugin-scope
Oct 8, 2026
Merged

bguidolim merged 3 commits into
mainfrom
bruno/ISSUE-450-plugin-scope

Conversation

@bguidolim

@bguidolim bguidolim commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The enabledPlugins entry mcs wrote used a key Claude Code ignores, so plugins only worked because claude plugin install enabled them for every project, and doctor could pass for a disabled plugin. Plugins now install at the sync's own scope and the Claude CLI alone manages enablement.

Closes #450

Release note

  • FIX: mcs doctor reports whether a plugin actually loads, instead of passing on a settings key Claude Code ignores. A plugin you disabled is a warning with the command to enable it
  • Plugins from a project's packs are now installed for that project only; a global sync still installs them for every project. A copy an earlier release installed for every project is left in place, and sync prints the command to remove it

Changes

  • Plugins install by their full name@marketplace id at the sync's scope; a plugin whose marketplace can't be found is skipped with a warning
  • mcs no longer writes enabledPlugins, and project sync keeps what the CLI wrote there
  • Only installs mcs made are recorded, on the pack that made them; removal uninstalls from that scope unless another pack in it still declares the plugin, which then takes over ownership
  • A plugin a pack update stops declaring is uninstalled; an uninstall counts as done once the plugin is no longer listed at that scope
  • mcs doctor --fix re-reads the plugin list after the re-sync, so a reinstalled plugin is reported fixed
  • Global sync saves settings.json whenever it stripped a pack's old keys, so legacy bare enabledPlugins entries are removed

Test plan

  • swift test passes locally

  • swiftformat --lint . and swiftlint pass without violations

  • Affected commands verified with a real pack (e.g. mcs sync, mcs doctor)

  • mcs sync a pack with a plugin: in a project → expect installed (scope: local), and claude plugin list --json shows it enabled only inside that project

  • mcs doctor there → expect enabled (project)

  • mcs pack remove <pack> → expect the local install removed, any user-scope copy untouched

Checklist for engine changes
  • Integration tests updated for new features (LifecycleIntegrationTests or DoctorRunnerIntegrationTests)
  • Docs updated if behavior changed (CLAUDE.md, docs/, techpack.yaml schema in ExternalPackManifest.swift)

…ement

- Stop writing enabledPlugins; Claude Code ignored the bare-name key, and project settings now keep what the CLI wrote
- Install by name@marketplace at the sync's scope (local in a project, user globally), recording only installs mcs made
- Doctor reads the CLI's plugin list, once per run, listing the global scope from the home directory
…d doctor --fix

- Uninstall a plugin a pack stops declaring; a kept plugin moves to the pack still claiming it
- Treat an uninstall as done when the plugin is no longer listed at the scope, and never claim an install made blind
- Doctor re-lists plugins after a re-sync and warns on disabled ones; global sync saves stripped legacy keys
@bguidolim
bguidolim force-pushed the bruno/ISSUE-450-plugin-scope branch from caf3e2f to 3b81e5d Compare October 8, 2026 15:55
- A disabled copy at another scope no longer turns a missing install into a warning, so doctor --fix reinstalls it
- Another project's project-scope install no longer counts for this project
@bguidolim
bguidolim merged commit 01c877a into main Oct 8, 2026
5 checks passed
@bguidolim
bguidolim deleted the bruno/ISSUE-450-plugin-scope branch October 8, 2026 19:03
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.

Plugin enablement is written under a key Claude Code ignores, and project syncs install plugins globally

1 participant