Claude Code’s v2.1.1431, released May 15, 2026, adds enforcement to the plugin dependency graph: claude plugin disable now refuses to disable a plugin if another enabled plugin declares it as a dependency, and claude plugin enable automatically pulls in all transitive dependencies. Before this update, both operations were silent about dependency state, leaving users to discover broken configurations at runtime.
What the Enforcement Actually Does
When you run claude plugin disable on a plugin that another enabled plugin depends on, the command exits with an error and prints a pre-formatted disable chain: the exact sequence of claude plugin disable calls needed to unwind the dependency graph in order. The hint is copy-pasteable, which is either convenient or an acknowledgment that multi-step dependency unwinding is now a real user workflow.
claude plugin enable silently pulls all transitive dependencies and installs them automatically if they are not already present. According to the plugins reference docs2, this covers both bare-string dependencies and versioned ones using semver constraints.
The Dependency Schema
Plugin authors declare dependencies in their manifest:
"dependencies": ["helper-lib", { "name": "secrets-vault", "version": "~2.1.0" }]Bare strings mean “any version”; the object form adds an optional semver constraint. The plugins reference2 confirms both forms are valid. What the schema does not yet specify: conflict resolution when two plugins require incompatible version ranges of the same dependency, or lockfile semantics. The manifest spec is sufficient to trigger enforcement, not sufficient to prevent a dependency hell scenario.
The Three-Week Arc
The disable/enable enforcement in v2.1.143 is not the first piece of this infrastructure. claude plugin prune, which removes orphaned auto-installed dependencies (also accessible as claude plugin autoremove), shipped in v2.1.121 on April 283. The full flow, auto-install on enable, prune on disable, block on unsafe disable, was assembled in stages over roughly three weeks. plugin uninstall --prune extends this by cascading removal through the dependency chain on explicit uninstall.
apt, Not the VS Code Extension Store
The VS Code extension model treats every extension as independent. No extension declares formal runtime dependencies on another in a way the host enforces; they coexist or conflict at runtime, and users manage failures manually. Claude Code’s enforcement is closer to apt or npm: the host resolves and enforces a declared dependency graph, auto-installs transitive deps, and refuses operations that would leave the graph in a broken state.
That shift has a cost. The VS Code approach is casual to author against: write an extension, publish it, users install it. The npm approach requires correctly declaring your dependencies, versioning them with care, and accepting that a bad semver range will surface as a user-visible error rather than a quiet runtime surprise. Plugin authors who have been vague about dependency declarations will find that sloppiness exposed now.
The Author Burden Shifts
Prior to this update, a plugin that implicitly relied on helper-lib being installed worked fine as long as the user happened to have it. A fresh profile missing helper-lib would produce a runtime error with no guidance. Disable enforcement and auto-install on enable flip this: if helper-lib is declared, it is guaranteed present on enable; if another plugin depends on yours, you cannot be disabled without an explicit chain.
The failure mode moves from silent runtime breakage to explicit install-time or disable-time error. That is strictly better for users, and strictly more demanding on authors, who now need a correct manifest or their users will encounter errors they cannot easily diagnose.
The Resolver Fight That Comes Next
Once a plugin ecosystem has a formal dependency graph and enforcement, the next pressure point is conflict resolution. npm has had this fight since 2010; apt still has it. Claude Code’s current spec has semver constraints and transitive auto-install but no stated policy on version conflicts, no lockfile, and no resolution algorithm. The plugin creation guide4 does not describe what a plugin author should do when their dependency requirements overlap with another plugin’s incompatibly.
This is viable as long as dependencies do not conflict. As the plugin ecosystem grows and plugins start sharing infrastructure dependencies, version conflicts will arrive. When they do, the question of whether Claude Code resolves them npm-style (nested installs per dependent) or apt-style (force a single shared version) will determine how much pain casual plugin authors absorb. npm’s nested model avoids conflicts at the cost of bloat and node_modules archaeology; apt’s single-version model is clean until two packages need incompatible versions of the same lib. Anthropic has not signaled which direction they intend to go, and the v2.1.143 release notes1 don’t hint at one.
Frequently Asked Questions
Does the plugin manifest support optional or dev-only dependencies?
No. The manifest exposes a single dependencies field with no equivalent of npm’s devDependencies or optionalDependencies. Every declared dependency is treated as required and enforced uniformly, so a plugin that can degrade gracefully when a dependency is absent has no way to express that in the manifest.
What should plugin authors do right now to avoid breaking user installs?
Audit runtime imports against the manifest and backfill any missing dependencies entries. A plugin that calls into another plugin’s exports without declaring that relationship works fine on existing installs where the transitive dependency is already present, but produces an unguarded runtime error for new users installing via claude plugin enable on a fresh profile.
How does claude plugin prune differ from npm prune?
npm prune strips everything not listed in package.json from node_modules. claude plugin prune only removes auto-installed transitive dependencies whose parent was already removed — it will not touch manually installed plugins regardless of whether anything references them. The scope is strictly orphan cleanup, not full tree reconciliation.
What specifically happens when enable encounters a conflicting version of a dependency?
The behavior is undefined in the current spec. npm handles this by installing nested copies (each dependent gets its own version tree), and apt refuses the install outright, enforcing a single system-wide version. Claude Code’s enable command auto-installs missing transitive deps but has no documented policy when a required semver range conflicts with an already-installed version. The enable may silently accept an incompatible version or fail — neither outcome is specified in the plugins reference.
What historical precedent suggests Claude Code will need a lockfile mechanism?
npm introduced package-lock.json in npm v5 (2017) because transitive dependency versions resolved differently across installs, breaking reproducibility. The same pressure applies here: once plugins share infrastructure dependencies like auth libraries or API clients, semver range resolution can produce different resolved versions on different machines. Without a lockfile or pinned manifest, two installs of the same plugin graph are not guaranteed to be identical.