## Why The initial research pass focused on agent definitions. An audit identified critical and minor gaps in both doc sets around plugin publishing, marketplace registration, and the Copilot extensibility model. ## Implementation Notes Claude Code gaps filled: end-to-end publish walkthrough (scaffold → validate → tag → host → register), CLI vs in-session command surface equivalence, all six marketplace source URL formats, plugin update/upgrade lifecycle, interactive plugin manager UI, private marketplace auth, `commands` vs `skills/` distinction. Copilot gaps filled: discovered that the GitHub App-based Copilot Extensions track was sunset November 2025. Created copilot-extensions.md as historical reference (deprecated, with MCP servers as the current replacement path). Documented the agent vs. skillset extension type distinction, OAuth install flow, and VS Code Chat Participants as the surviving @mention mechanism. overview.md updated with a "Which Track to Use" decision table covering all four active tracks plus the deprecated one. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
5.2 KiB
topic, source_keys
| topic | source_keys | |||
|---|---|---|---|---|
| configuration |
|
Plugin Manifest (plugin.json)
The manifest lives at .claude-plugin/plugin.json in the plugin root directory. It is optional — components are auto-discovered without it — but required for namespacing, versioning, and marketplace distribution.
{
"name": "plugin-name",
"displayName": "Plugin Name",
"version": "1.2.0",
"description": "Brief plugin description",
"author": {
"name": "Author Name",
"email": "author@example.com",
"url": "https://github.com/author"
},
"homepage": "https://docs.example.com/plugin",
"repository": "https://github.com/author/plugin",
"license": "MIT",
"keywords": ["keyword1", "keyword2"],
"skills": "./custom/skills/",
"commands": ["./custom/commands/special.md"],
"agents": ["./custom/agents/reviewer.md"],
"hooks": "./config/hooks.json",
"mcpServers": "./mcp-config.json",
"outputStyles": "./styles/",
"lspServers": "./.lsp.json",
"experimental": {
"themes": "./themes/",
"monitors": "./monitors.json"
},
"dependencies": [
"helper-lib",
{ "name": "secrets-vault", "version": "~2.1.0" }
]
}
name — Required for namespacing. Skills under this plugin are invoked as /plugin-name:skill-name. Must be unique across installed plugins.
version — Optional string. If omitted, the git commit SHA is used and every commit is treated as a new version.
author — Optional object with name, email, and url.
All path values in the manifest are relative to the plugin root.
commands vs skills
The manifest supports two fields that both register slash-command-style invocations, but they use different formats and have different capabilities:
| Feature | skills |
commands |
|---|---|---|
| Format | skills/<name>/SKILL.md directory per skill |
Single .md files listed as paths |
| Invocation | /plugin-name:skill-name (namespaced) |
/command-name (global, no namespace) |
| Autonomous use by Claude | Yes — Claude can invoke without an explicit / command |
No — only user-typed / triggers it |
| Status | Recommended | Legacy |
The commands field is the legacy slash-command format. It accepts an array of paths to individual Markdown files:
"commands": ["./custom/commands/special.md"]
Each file is a single command definition equivalent to a .md file in .claude/commands/. The command is invoked as /filename (without the extension).
The skills field is the recommended replacement. A skill directory (skills/<name>/SKILL.md) provides the same /name invocation plus autonomous invocation by Claude (Claude can call the skill proactively without the user typing a / command). Skills also support bundling supporting files alongside SKILL.md.
Practical rule: use skills/ for new plugin content. The commands field exists for backward compatibility when porting legacy .claude/commands/ files into a plugin. The CLI supports both formats.
Plugin settings.json
A settings.json at the plugin root applies default settings when the plugin is enabled. Currently supports only two keys:
{
"agent": "security-reviewer",
"subagentStatusLine": true
}
agent — Activates a named agent from the plugin's agents/ directory as the main session thread, replacing the default Claude Code system prompt with the agent's system prompt, tool restrictions, and model. Project and user .claude/agents/ definitions with the same name override this.
Settings in settings.json take priority over settings declared inside plugin.json.
Plugin Directory Layout
All content directories must be at the plugin root, not inside .claude-plugin/:
| Directory / File | Purpose |
|---|---|
skills/<name>/SKILL.md |
Skills (namespaced as /plugin-name:skill-name) |
agents/ |
Agent definition markdown files |
hooks/hooks.json |
Event handlers (PreToolUse, PostToolUse, etc.) |
.mcp.json |
MCP server definitions |
.lsp.json |
LSP server definitions |
monitors/monitors.json |
Background shell monitors |
bin/ |
Executables added to the Bash tool's PATH |
settings.json |
Default settings applied when plugin enabled |
Agent Activation as Main Thread
Setting agent in settings.json (or in .claude/settings.json for project scope) makes a subagent the default for every session:
// .claude/settings.json or plugin settings.json
{
"agent": "my-specialist-agent"
}
The named agent must exist in an agents/ directory accessible to that scope. When activated this way, the agent's initialPrompt field is auto-submitted as the first user turn.
Disabling Subagents
Add Agent(subagent-name) to permissions.deny in settings.json to block specific subagents. To block all subagent delegation, deny the Agent tool itself.
In non-interactive/SDK mode, set CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS=1 to remove all built-ins.
Model Configuration
CLAUDE_CODE_SUBAGENT_MODEL=<model-id> # global override for all subagents
Resolution order: env var → per-invocation model parameter → frontmatter model → main session model.