Skip to content

feat(plugins): add Claude Code marketplace plugin compatibility#5

Merged
Zetkolink merged 5 commits intomainfrom
feat/claude-code-marketplace-plugin-compat-v2
Apr 11, 2026
Merged

feat(plugins): add Claude Code marketplace plugin compatibility#5
Zetkolink merged 5 commits intomainfrom
feat/claude-code-marketplace-plugin-compat-v2

Conversation

@Zetkolink
Copy link
Copy Markdown
Owner

Summary

Add full compatibility with Claude Code marketplace plugin directory structure, enabling Forge to discover, install, and run plugins designed for Claude Code's ecosystem.

Context

When installing a Claude Code marketplace plugin (e.g. claude-mem from ~/.claude/plugins/marketplaces/thedotmack), Forge showed all components as 0/none despite the plugin containing skills, hooks, MCP servers, and modes. The root cause: Claude Code marketplace repositories use a nested layout where marketplace.json points to the actual plugin subdirectory (e.g. ./plugin/), but Forge only looked for components at the repository root.

Additionally, Claude Code plugins reference $CLAUDE_PLUGIN_ROOT, $CLAUDE_PROJECT_DIR, and $CLAUDE_SESSION_ID in their hook commands and MCP server definitions — variables that Forge didn't provide.

Changes

Marketplace Discovery (Runtime + Install)

  • Added MarketplaceManifest / MarketplacePluginEntry domain types for parsing marketplace.json
  • Extended scan_root to detect marketplace indirection: when a directory lacks a direct plugin manifest but contains marketplace.json, the loader follows the source field to find the real plugin
  • Added container directory scanning for cache/ and marketplaces/ layouts used by Claude Code's plugin manager
  • Updated forge plugin install to resolve marketplace structure, count components from the effective plugin root, and copy only the plugin subdirectory (not the entire repo)

MCP Sidecar Counting

  • Trust prompt now counts MCP servers from .mcp.json sidecar file in addition to plugin.json manifest — matching how the runtime loader already works

Environment Variable Aliases

  • Injected CLAUDE_PLUGIN_ROOT, CLAUDE_PROJECT_DIR, and CLAUDE_SESSION_ID as aliases alongside their FORGE_* counterparts for both hook subprocesses and MCP server processes
  • Claude Code plugins referencing ${CLAUDE_PLUGIN_ROOT} in hook commands now work under Forge without modification

Modes Display

  • Added modes count to trust prompt, /plugin info, and /plugin list output — Claude Code plugins often ship dozens of operational modes

Flaky Test Fixes

  • test_format_path_for_display_no_home: explicitly set home to None instead of relying on Faker-generated random value that could collide with test paths
  • test_hook_exit_before_prompt_response_does_not_hang: increased elapsed threshold from 3s to 4s to account for parallel test load while still validating no-hang behavior

Use Cases

  • forge plugin install ~/.claude/plugins/marketplaces/thedotmack correctly resolves the nested plugin, showing accurate component counts (skills: 7, hooks: present, MCP servers: 1, modes: 36)
  • Runtime discovery of ~/.claude/plugins/ automatically finds plugins inside marketplaces/<author>/ via marketplace.json indirection
  • Hooks using ${CLAUDE_PLUGIN_ROOT}/scripts/worker.cjs execute correctly with the variable resolved to the plugin's installed directory

Testing

# Run all new and affected tests
cargo nextest run --no-input-handler --lib -p forge_domain -- test_parse_marketplace
cargo nextest run --no-input-handler --lib -p forge_repo -- marketplace
cargo nextest run --no-input-handler --lib -p forge_main -- test_marketplace
cargo nextest run --no-input-handler --lib -p forge_main -- test_mcp_sidecar
cargo nextest run --no-input-handler --lib -p forge_services -- hook_runtime::env
cargo nextest run --no-input-handler --lib -p forge_services -- mcp::manager::tests

# Previously flaky tests — should now be stable
cargo nextest run --no-input-handler --lib -p forge_main -- test_format_path_for_display_no_home
cargo nextest run --no-input-handler --lib -p forge_services -- test_hook_exit_before_prompt_response_does_not_hang

23 new/updated tests added across 6 crates.

- Add MarketplaceManifest deserialization type for marketplace.json
- Add marketplace-aware scanning to scan_root (resolves nested plugins
  via marketplace.json source field)
- Handle cache/ and marketplaces/ container directory layouts for
  Claude Code plugin discovery
- Detect marketplace indirection during forge plugin install
- Count MCP servers from .mcp.json sidecar in trust prompt
- Copy only effective plugin root during install (not entire repo)
- Add CLAUDE_PLUGIN_ROOT env var alias for hook and MCP subprocesses
- Add CLAUDE_PROJECT_DIR and CLAUDE_SESSION_ID env var aliases
- Add modes count to trust prompt, /plugin info, and /plugin list
- Add marketplace plugin test fixture and comprehensive tests
- test_format_path_for_display_no_home: explicitly set home to None
  instead of relying on Faker-generated random value
- test_hook_exit_before_prompt_response_does_not_hang: increase
  elapsed threshold from 3s to 4s to account for parallel test load
@github-actions github-actions bot added the type: feature Brand new functionality, features, pages, workflows, endpoints, etc. label Apr 11, 2026
autofix-ci bot and others added 3 commits April 11, 2026 17:47
Root cause: .gitignore line 44 contains '.mcp.json' which prevented
the test fixture at marketplace_author/plugin/.mcp.json from being
committed. Test passed locally (file existed on disk) but failed on
CI (file missing from git checkout).

Fix: git add -f the specific fixture file.
@Zetkolink Zetkolink merged commit 25306eb into main Apr 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Brand new functionality, features, pages, workflows, endpoints, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant