Lessons Learned from Building Modular, Extendable Claude Code Plugins As of August 2026, Anthropic's Claude Code plugin system supports hard dependencies but lacks optional or soft dependencies, prompting developer Eigenwise to build a modular plugin marketplace where five of seven plugins read the undocumented install ledger at ~/.claude/plugins/installed_plugins.json to enable graceful degradation. The Eigenwise Toolshed marketplace includes plugins like Sidequest, Model Gateway, Observability, and Workbench, which interoperate without any manifest naming another plugin, relying on the registry to resolve optional integrations. Lessons Learned from Building Modular, Extendable Claude Code Plugins Today, there are seven plugins in my Eigenwise Toolshed https://github.com/Eigenwise/eigenwise-toolshed marketplace. Install any one of them on its own and it works on its own. Install the right second one and something quietly gets better, without either plugin having been told the other existed. Most of that wiring converges on one of them. Sidequest is the ticket board, and it’s the peer the others reach for: Model Gateway hands it models it never had to know about , Observability pulls cost and ticket data straight out of its database, Workbench audits its boards and worktrees at session start. Three plugins reaching for the same neighbour, and not one manifest in that repo names another plugin. That was on purpose, and the constraint is where all the interesting design ended up going. First of a few notes from the shed. Starting with the modularity, because it’s the part I’d most want someone else to steal. Where the Official Road Ends Claude Code has a real plugin dependency system, and it’s better than I expected when I went looking . As of August 2026, plugin.json takes a dependencies array https://code.claude.com/docs/en/plugin-dependencies : { "name": "deploy-kit", "version": "3.1.0", "dependencies": "audit-logger", { "name": "secrets-vault", "version": "~2.1.0" } } Ranges resolve against git tags, and when several plugins constrain the same dependency it intersects the ranges and throws range-conflict if they can’t agree. It also blocks cross-marketplace dependencies unless the root marketplace allowlists the target, enables transitively, refuses to disable something another enabled plugin still needs, and ships claude plugin prune for the orphans. As of August 2026, no other agent CLI documents anything close , and I went and looked at Codex CLI , Gemini CLI , Cursor and Copilot CLI before saying that. It’s a hard dependency, though. A plugin whose dependency isn’t satisfied gets disabled until you fix it . Which is right for “this cannot function without that.” It’s no use at all for “this gets better when that happens to be around,” and that second one is the case I actually had. The runtime side gives you nothing to work with. There’s no enumeration call, and nothing in the environment a hook receives names any plugin but itself : you get CLAUDE PLUGIN ROOT , CLAUDE PLUGIN DATA and CLAUDE PLUGIN OPTION