Skip to main content

Module 12 — Plugins and marketplaces: package and share your tooling

The previous modules built separately what makes Claude Code valuable inside a team: skills, subagents, hooks, MCP servers. Each piece lives in its own corner. The closing module brings them together: a plugin is the single package that groups everything, versioned, installable in one command, shareable through a marketplace. It is the format to favor as soon as a team exceeds two people.

Plugin or standalone configuration?

Stay on standalone .claude/ when the content is specific to a repo. Move to a plugin when the piece is reusable across projects, must be versioned independently, must install on other teams, or groups several components (skill + subagent + hooks + MCP server).

A plugin can pack everything: skills, subagents, workflows, hooks, MCP servers, LSP servers, monitors, themes, output styles, executables. It exposes all of them under a namespace (kiosque-tools:deploy) that avoids collisions.

Anatomy of a plugin

A plugin is a folder with a single manifest at .claude-plugin/plugin.json. Every other component lives at the plugin root, not inside .claude-plugin/. A frequent confusion: putting agents/ or hooks/ inside .claude-plugin/ — Claude Code will not find them.

Reference structure:

my-plugin/
├── .claude-plugin/
│ └── plugin.json # Manifest (optional if everything is at the default locations)
├── skills/ # <name>/SKILL.md per skill
│ └── deploy/SKILL.md
├── commands/ # Skills as flat .md files (compatible; prefer skills/)
├── agents/ # Subagents (.md with frontmatter)
│ └── reviewer.md
├── workflows/ # Dynamic workflows
├── hooks/
│ └── hooks.json # Plugin hooks
├── .mcp.json # MCP servers provided by the plugin
├── .lsp.json # LSP servers
├── monitors/monitors.json # Background monitors
├── bin/ # Executables added to PATH when the plugin is active
└── settings.json # Default settings (only `agent` and `subagentStatusLine` keys are read)

A plugin that only exposes one skill can put SKILL.md directly at the plugin root, without a skills/ folder. For anything that grows, use skills/<name>/SKILL.md.

The plugin.json manifest

Only name is required, and the manifest itself is optional: without it, Claude Code discovers components at the default locations and derives the name from the folder. A minimal manifest:

{
"name": "kiosque-tools",
"displayName": "Kiosque Tools",
"version": "1.0.0",
"description": "Kiosque internal tooling: review, tests, deployment.",
"author": { "name": "Kiosque team", "email": "dev@kiosque.example" }
}

Excerpt of documented fields:

FieldRole
namekebab-case identifier, serves as namespace (kiosque-tools:deploy)
displayName / descriptionShown in /plugin
versionSemver; pins the install
author, homepage, repository, license, keywordsDiscovery metadata
defaultEnabledfalse = installs disabled (opt-in)
skills, commands, agents, workflows, hooks, mcpServers, lspServersCustom paths to components
dependenciesOther required plugins, with semver constraints
userConfig, channelsUser configuration, messaging channels
experimental.themes, experimental.monitorsComponents with an evolving schema

Unknown root fields are ignored — useful for coexisting with a npm package.json.

Three key environment variables

  • ${CLAUDE_PLUGIN_ROOT} — absolute path of the install folder. For packaged scripts and binaries.
  • ${CLAUDE_PLUGIN_DATA} — persistent folder that survives updates (~/.claude/plugins/data/{id}/). For dependencies installed at first use.
  • ${CLAUDE_PROJECT_DIR} — project root.

All three are exported to hook, MCP, and LSP processes, and substituted in the content of skills, agents, hook/monitor commands, command/args/env of a stdio MCP, url/headers of an HTTP one.

Develop, test, reload

Four commands set the development rhythm.

  • Bootstrap: claude plugin init <name> creates a plugin in ~/.claude/skills/<name>/ with a manifest and a starter SKILL.md, loaded at the next session.
  • Local testing: claude --plugin-dir ./my-plugin loads the plugin for the session. Stackable for several plugins. If the name conflicts with an installed plugin, the local copy takes precedence.
  • Reload: /reload-plugins applies changes (skills, subagents, hooks, MCP, LSP) without restarting. --force accepts the prompt cache invalidation.
  • Validate: claude plugin validate ./my-plugin --strict in CI.

In session, /plugin opens the manager: Installed, Discover, Errors tabs, favorites (key f), name filter.

Marketplaces: find and distribute

A plugin is rarely installed through --plugin-dir in production; it comes from a marketplace, a catalog of plugins you add once and then install entries from at will.

Official marketplaces and adding sources

Two public marketplaces maintained by Anthropic: claude-plugins-official (registered automatically on the first interactive session) and claude-community (third-party submissions after review, add with /plugin marketplace add anthropics/claude-plugins-community).

Four possible sources to add:

/plugin marketplace add owner/repo                              # GitHub
/plugin marketplace add https://gitlab.com/company/plugins.git # Git (https:// + .git)
/plugin marketplace add ./my-marketplace # Local path
/plugin marketplace add https://example.com/marketplace.json # Remote JSON

Shortcut: /plugin market. Target a branch: .../plugins.git#v1.0.0.

Installing a plugin

/plugin install kiosque-tools@my-marketplace

Three scopes offered: User (all your projects), Project (shared, added to versioned .claude/settings.json), Local (you only). Since v2.1.221, the install sometimes activates the plugin in the current session; otherwise the prompt says Run /reload-plugins to activate.

To distribute internally, host the marketplace in a private repository; Claude Code uses your Git credentials to clone. Administrators can force a marketplace through managed settings (extraKnownMarketplaces).

Kiosque: the complete kiosque-tools plugin

The Kiosque team consolidates what it built in modules 9 to 11 into a single plugin, published in a private marketplace kiosque/internal-plugins.

Plugin structure

kiosque-tools/
├── .claude-plugin/
│ └── plugin.json
├── skills/
│ └── deploy/SKILL.md
├── agents/
│ ├── reviewer.md
│ └── tester.md
├── hooks/
│ └── hooks.json
├── .mcp.json
├── bin/
│ └── format-python.sh
└── README.md

plugin.json

{
"name": "kiosque-tools",
"displayName": "Kiosque Tools",
"version": "1.0.0",
"description": "Kiosque internal tooling: code review, tests, deployment, GitHub and Postgres access.",
"author": {
"name": "Kiosque team",
"email": "dev@kiosque.example",
"url": "https://kiosque.example"
},
"homepage": "https://kiosque.example/docs/plugin",
"repository": "https://gitlab.kiosque.example/dev/kiosque-tools",
"license": "UNLICENSED",
"keywords": ["kiosque", "review", "deploy", "postgres", "github"],
"defaultEnabled": true
}

hooks/hooks.json

Module 9's three hooks, this time portable: ${CLAUDE_PLUGIN_ROOT} replaces ${CLAUDE_PROJECT_DIR} for the embedded script, and the scripts against migrations/ and tests stay tied to the project.

{
"hooks": {
"PostToolUse": [
{ "matcher": "Edit|Write", "hooks": [
{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/bin/format-python.sh" }
]}
],
"PreToolUse": [
{ "matcher": "Edit|Write", "hooks": [
{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/protect-paths.sh" }
]}
],
"Stop": [
{ "hooks": [
{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/require-green-tests.sh", "timeout": 300 }
]}
]
}
}

Note: Python formatting lives in the plugin (bin/format-python.sh), common to every Kiosque project. Hooks specific to the repo (path protection, local tests) stay in ${CLAUDE_PROJECT_DIR} — that is the rule: what varies per project stays per project.

.mcp.json

Module 11's MCP server becomes an integral part of the plugin. Secrets stay outside, in ${VAR}:

{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_MCP_TOKEN}" }
},
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${KIOSQUE_DB_DSN}"]
}
}
}

Subagents and skill

agents/reviewer.md and agents/tester.md reuse module 10's definitions, except they are now namespaced as kiosque-tools:reviewer and kiosque-tools:tester. Karim invokes them with @"kiosque-tools:reviewer (agent)".

skills/deploy/SKILL.md captures the recurring deployment:

---
description: Deploys the current version of Kiosque to the staging environment.
---

# /kiosque-tools:deploy

Chains the staging deployment steps:
1. Confirms the branch is clean (`git status --porcelain`).
2. Builds the Docker image tagged with the short SHA.
3. Pushes the image to `registry.kiosque.example`.
4. Updates the Kubernetes manifest and restarts the deployment.
5. Waits for `Ready` then runs the smoke suite `make smoke`.

Uses the `github` and `postgres` MCP servers declared by this plugin to check,
respectively, PR compliance and the health of the staging database.

Publish and install

Nadia commits kiosque-tools/ in the repo gitlab.kiosque.example/dev/internal-plugins, with a .claude-plugin/marketplace.json at the root that lists the team's plugins. Each developer adds the marketplace only once:

/plugin marketplace add https://gitlab.kiosque.example/dev/internal-plugins.git
/plugin install kiosque-tools@internal-plugins

Karim sees an install summary, picks the User scope (he wants the plugin in every Kiosque project). If the message says Run /reload-plugins to activate., he types the command. From the current session, /kiosque-tools:deploy, @"kiosque-tools:reviewer (agent)" and the hooks work.

A month later, the team ships 1.1.0 with a new subagent. Nadia bumps version, tags, pushes. Colleagues pick up the update on the next session, or immediately through /plugin marketplace update internal-plugins then /reload-plugins.

One plugin, many projects

An ideal team plugin is project-agnostic: what works everywhere goes into the plugin, what varies per repo stays in the repo's .claude/. This separation avoids the antipattern "the plugin that knows everything about Kiosque and works nowhere else."

Summary

  • A plugin packages skills, subagents, workflows, hooks, MCP and LSP servers, monitors, themes, and executables under a single namespace.
  • Structure: .claude-plugin/plugin.json for the manifest; everything else at the plugin root, never inside .claude-plugin/.
  • Minimal manifest: name (kebab-case, serves as namespace). Useful fields: displayName, version, description, defaultEnabled, dependencies.
  • Variables: ${CLAUDE_PLUGIN_ROOT} (install), ${CLAUDE_PLUGIN_DATA} (persistent), ${CLAUDE_PROJECT_DIR} (project).
  • Development: claude plugin init, --plugin-dir to test, /reload-plugins to apply changes, claude plugin validate --strict in CI.
  • Marketplaces: official (claude-plugins-official, claude-community); custom sources through /plugin marketplace add (GitHub, Git URL, local path, remote marketplace.json).
  • Install: /plugin install <plugin>@<marketplace> with choice of scope User / Project / Local. /plugin opens the full manager.
  • For Kiosque, a kiosque-tools plugin bundles portable hooks, reviewer and tester subagents, GitHub and Postgres MCP servers, and a deploy skill — versioned in a private team marketplace.

Next module: Daily workflows: explore, fix, test, review, ship — how to chain all these tools through a typical day of engineering.