claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[FEATURE] Support for Plugin Dependencies and Shared Resources

Open jawhnycooke opened this issue 3 months ago • 8 comments

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

Summary

Add support for plugin dependencies and shared resource libraries to the Claude Code plugin system, enabling plugins to declare dependencies on other plugins or common libraries.

Motivation

Current Limitation

Today, plugins are completely independent units. If multiple plugins need the same agents, hooks, or utilities, each plugin must duplicate these resources. This leads to:

  1. File duplication - Same agent definitions copied across multiple plugins
  2. Maintenance burden - Updates must be applied to all copies
  3. Inconsistency risk - Copies can drift out of sync
  4. Storage waste - duplicated agents in the marketplace

Real-World Example

Our marketplace has 11 plugins. We had to copy 32 agents across 7 plugins because:

  • @code-archaeologist is used by: epcc-workflow, documentation, architecture, tdd-workflow, performance
  • @security-reviewer is used by: epcc-workflow, architecture, tdd-workflow, security
  • @test-generator is used by: epcc-workflow, documentation, architecture, tdd-workflow, testing

Without dependencies: Copy 32 agents = duplication With dependencies: 1 common-core plugin = no duplication Pros: Simple, no changes needed Cons: Maintenance burden, inconsistency risk Verdict: ❌ Not scalable as marketplace grows

2. Documentation-Only Dependencies

Tell users "install common-core first" Pros: No code changes Cons: ❌ Not enforced, easy to miss, poor UX Verdict: ❌ Unreliable

3. Monolithic Plugins

Make each plugin completely self-contained Pros: Always works Cons: ❌ Massive duplication (current solution) Verdict: ✅ Good short-term, ❌ bad long-term

Related Issues

  • Plugin system scalability
  • Marketplace organization
  • Plugin development experience

Proposed Solution

Proposed Solution

1. Plugin Dependencies in Manifest

Add dependencies field to plugin.json:

{
  "name": "epcc-workflow",
  "version": "1.0.0",
  "dependencies": {
    "common-core": "^1.0.0",
    "security-core": "^2.1.0"
  },
  "agents": ["agents/"],
  "commands": ["commands/"]
}

2. Common Resource Plugins

Allow plugins to declare themselves as libraries:

{
  "name": "common-core",
  "version": "1.0.0",
  "type": "library",
  "description": "Common agents used across multiple plugins",
  "agents": ["agents/"],
  "exports": {
    "agents": [
      "code-archaeologist",
      "system-designer",
      "business-analyst"
    ]
  }
}

3. Automatic Dependency Resolution

When installing a plugin:

/plugin install epcc-workflow@claude-code-plugins

# Claude Code automatically:
✓ Resolving dependencies...
✓ Installing [email protected]
✓ Installing [email protected]
✓ Installing [email protected]
✓ All dependencies satisfied

4. Shared Resource Directory Structure

~/.claude/plugins/
├── [email protected]/
│   ├── commands/
│   └── .claude-plugin/plugin.json  # declares dependencies
├── [email protected]/
│   ├── agents/
│   │   ├── code-archaeologist.md
│   │   └── system-designer.md
│   └── .claude-plugin/plugin.json  # type: "library"

Plugins can reference shared agents:

# From epcc-workflow commands
@code-archaeologist  # Resolves from common-core dependency

Benefits

For Plugin Authors

  • DRY principle - Define agents once, reuse everywhere
  • Easier maintenance - Update one file, all plugins benefit
  • Smaller plugins - Plugins only contain unique resources
  • Clear dependencies - Explicit dependency graph

For Users

  • Automatic installation - Dependencies installed transparently
  • Faster installs - Shared resources downloaded once
  • Consistency - Same agent version across all plugins
  • Better reliability - Fewer missing dependency errors

For Marketplace

  • Scalability - More plugins without N² duplication
  • Quality - Centralized, well-tested common resources
  • Organization - Clear separation of concerns

Design Considerations

Dependency Resolution

  • Semver support - "^1.0.0", "~2.1.0", ">=1.5.0"
  • Circular dependency detection - Fail with clear error
  • Version conflicts - Choose highest compatible version
  • Peer dependencies - Optional for flexibility

Performance

  • Lazy loading - Only load dependencies when needed
  • Caching - Shared resources cached for speed
  • Parallel installs - Install dependencies concurrently

Backwards Compatibility

  • Optional feature - Plugins without dependencies still work
  • Graceful degradation - Fall back to bundled resources if dependency unavailable
  • Migration path - Clear documentation for converting existing plugins

Alternative Solutions

Alternative Approaches Considered

1. Continue with Duplication (Current)

Pros: Simple, no changes needed Cons: Maintenance burden, inconsistency risk Verdict: ❌ Not scalable as marketplace grows

2. Documentation-Only Dependencies

Tell users "install common-core first" Pros: No code changes Cons: ❌ Not enforced, easy to miss, poor UX Verdict: ❌ Unreliable

3. Monolithic Plugins

Make each plugin completely self-contained Pros: Always works Cons: ❌ Massive duplication (current solution) Verdict: ✅ Good short-term, ❌ bad long-term

Related Issues

  • Plugin system scalability
  • Marketplace organization
  • Plugin development experience

Priority

Medium - Would be very helpful

Feature Category

Configuration and settings

Use Case Example

Real-World Example:

[AWS Advanced Agent Patterns] (https://github.com/aws-samples/anthropic-on-aws/tree/main/advanced-claude-code-patterns)

Our proposed marketplace has 11 plugins. We had to copy 32 agents across 7 plugins because:

  • @code-archaeologist is used by: epcc-workflow, documentation, architecture, tdd-workflow, performance
  • @security-reviewer is used by: epcc-workflow, architecture, tdd-workflow, security
  • @test-generator is used by: epcc-workflow, documentation, architecture, tdd-workflow, testing

Without dependencies: Copy 32 agents = duplication With dependencies: 1 common-core plugin = no duplication Pros: Simple, no changes needed Cons: Maintenance burden, inconsistency risk Verdict: ❌ Not scalable as marketplace grows

2. Documentation-Only Dependencies

Tell users "install common-core first" Pros: No code changes Cons: ❌ Not enforced, easy to miss, poor UX Verdict: ❌ Unreliable

3. Monolithic Plugins

Make each plugin completely self-contained Pros: Always works Cons: ❌ Massive duplication (current solution) Verdict: ✅ Good short-term, ❌ bad long-term

Examples from Other Systems

NPM/Node.js

{
  "dependencies": {
    "lodash": "^4.17.21"
  },
  "peerDependencies": {
    "react": ">=16.0.0"
  }
}

Python pip

install_requires=[
    'requests>=2.25.0',
    'numpy~=1.20.0'
]

VSCode Extensions

{
  "extensionDependencies": [
    "ms-python.python"
  ]
}

Additional Context

References

jawhnycooke avatar Oct 12 '25 22:10 jawhnycooke

they already sollved this you can have the resources in the market place root, and then use strict: false, and then the plugin config in the market place can define more granular assignments of command/agents/hooks

Andrews-repo avatar Oct 14 '25 05:10 Andrews-repo

they already sollved this you can have the resources in the market place root, and then use strict: false, and then the plugin config in the market place can define more granular assignments of command/agents/hooks

I would argue this is a work around, not a solution. In my opinion the solution would use the same @ reference already implemented but be context aware of the marketplace.

burneyhoel avatar Oct 19 '25 02:10 burneyhoel

they already sollved this you can have the resources in the market place root, and then use strict: false, and then the plugin config in the market place can define more granular assignments of command/agents/hooks

I tested this and, unless I am missing something, You cannot reference things at the market place root from a plugin due to the schema requirement that the plugin paths start with ./. see error below.

/plugin ⎿ Failed to load all marketplaces. Errors: test-marketplace: Invalid schema: plugins.0.skills.0: Invalid input: must start with "./",

"plugins": [
    {
        "name": "test",
        "source": "./plugins/test",
        "description": "test",
        "strict": false,
        "commands": [
            "./hello.md"
        ],
        "skills": [
            "../dep.md"
        ]
    },

Edit: I figured out how to reference, it requires raising the source path. It does not work with @ reference but does work with "use skill X". Still feels like a workaround, its not awesome.

burneyhoel avatar Oct 20 '25 00:10 burneyhoel

thank you @jawhnycooke...I was just about to file a feature request before I found yours

smar-sean-sekora avatar Nov 10 '25 20:11 smar-sean-sekora

Regarding the dependencies block

The current structure:

"dependencies": {
    "common-core": "^1.0.0",
    "security-core": "^2.1.0"
}

While this follows the familiar npm/PyPI pattern, it assumes a single centralized marketplace. To support multiple Claude Code Marketplaces/Plugins, including private/internal registries, I'd suggest a more flexible structure:

"dependencies": [
    {
        "name": "my-plugin",
        "version": "1.0.0",
        "source": "./plugins/my-plugin"
    },
    {
        "name": "my-other-plugin",
        "version": "1.0.1",
        "source": {
            "type": "git",
            "url": "https://gitlab.com/team/my-other-plugin.git"
        }
    },
]

This approach would:

  • Support local file paths for development/internal plugins
  • Enable git repositories as dependency sources
  • Allow custom registries/marketplaces

smar-sean-sekora avatar Nov 10 '25 22:11 smar-sean-sekora

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

github-actions[bot] avatar Dec 11 '25 10:12 github-actions[bot]

Building on what @smar-sean-sekora suggests, I might also add that local referenced plugins should probably not have a version. I'd probably consider the reference similar to github actions, where references to remote repos can use a tag or sha or branch.

I'd forsee some basic issues here though: when you have dependencies, how do you ensure those dependencies do their thing before you need to (eg hook ordering).

One thing that made me think about this was the potential for a plugin that contains a bunch of supporting rules, and an mcp server that syncs those rules in to the .claude folder for an org to use to sync rules. (the mcp server doesn't do anything, it just uses the execution to kick off the syncing process and potentially watch for updates on long running sessions)

To this end, I wanted to make a plugin that handled the basic ideas of the syncing and mcp server with no rules, and another plugin that depended on that other plugin to sync it's rules.

To help mitigate issues, perhaps plugins should opt in to being used as a dependency by stating in their schema that they take inputs, which then lets the depend-er define the dependency and then pass it's own info to the other plugin.

As I type this, while "dependencies" feels like the right term, the actuality is that this feels a bit more like github actions. Having the following as the schema would enact the above ideas:

"dependencies": [
    {
        "uses": "./plugins/rule-sync"
        "with": {
			"ruleRoot": "./rules" // relative to this plugin
		}
    },
    {
        "uses": "https://gitlab.com/team/[email protected]"
    },
    {
        "uses": "https://gitlab.com/team/my-other-plugin.git/subpath/to/[email protected]" // where the .claude-plugin folder lives
    },
    {
        "uses": "githuborg/github-repo" // default to sourcing from github, and from default branch
    },
]

The update to the schema for the plugins that can be depended on could look like:

"depdenencies": [
  {
  	// if this were to be installed rather than depended on, this is where it would define it's inputs
  	// If a plugin defines a reusable block, but doesn't depend on itself, then it doesn't do anything!
    // This ensures plugin use is intentional and won't break due to some things being missing.
    // Probably better to encourage an in-tree plugin that uses the reusable one instead of the
    // reusable one depending on itself?
    "uses": "./"
  }
]
"resusable": {  // presence indicates you can `use` it in another one
  "inputs": {
    "rulesRoot": {
      "type": "path", // so strings are mapped relative to the plugin that sent the input
      "required": true, // if the value isn't passed, this plugin fails to load and claude reports an error
      "default": "./rules", // the value (relative to the USING plugin) to use if not provided
      "mcp": {  // use this value in MCP configs
        "env": { // by setting an env var to expose it
            "RULES_ROOT_DIR": "${{ .value }}"
        }
       },
  	  "hooks": { /* ... */ }, // same as mcp, but expose for hooks
      "env": { // or set globally for things used within this plugin
        "RULES_ROOT_DIR": "${{ .value }}"
      }
    }
  }
}

nsheaps avatar Dec 20 '25 04:12 nsheaps

they already sollved this you can have the resources in the market place root, and then use strict: false, and then the plugin config in the market place can define more granular assignments of command/agents/hooks

I tested this and, unless I am missing something, You cannot reference things at the market place root from a plugin due to the schema requirement that the plugin paths start with ./. see error below.

/plugin ⎿ Failed to load all marketplaces. Errors: test-marketplace: Invalid schema: plugins.0.skills.0: Invalid input: must start with "./",

"plugins": [
    {
        "name": "test",
        "source": "./plugins/test",
        "description": "test",
        "strict": false,
        "commands": [
            "./hello.md"
        ],
        "skills": [
            "../dep.md"
        ]
    },

Edit: I figured out how to reference, it requires raising the source path. It does not work with @ reference but does work with "use skill X". Still feels like a workaround, its not awesome.

What if we use a git submodule placed inside the your own plugin folder, then it would look something like:

"plugins": [
    {
        "name": "test",
        "source": "./plugins/test",
        "description": "test",
        "strict": false,
        "commands": [
            "./hello.md"
        ],
        "skills": [
            "./{submodulename}/dep.md"
        ]
    },

Then, for updating it is not hard to set an action that auto-update submodules.

Did someone tried a workaround like this? Would that work?

jaodsilv avatar Dec 21 '25 13:12 jaodsilv