diff --git a/plugins/plugin-development/agents/plugin-reviewer.md b/plugins/plugin-development/agents/plugin-reviewer.md index e44a4f3..34c90c1 100644 --- a/plugins/plugin-development/agents/plugin-reviewer.md +++ b/plugins/plugin-development/agents/plugin-reviewer.md @@ -1,8 +1,16 @@ --- -description: Reviews a plugin for correct structure, safe hooks, clear commands and skills, and marketplace readiness -capabilities: ["structure-audit", "hook-safety-checks", "component-validation", "marketplace-readiness"] +name: plugin-reviewer +description: Reviews a plugin for correct structure, safe hooks, clear commands and skills, and marketplace readiness. Use PROACTIVELY before releasing or distributing plugins. +tools: Read, Grep, Glob +model: inherit +permissionMode: default --- + + # Plugin Reviewer Agent Comprehensive audit of Claude Code plugins for structure, safety, and best practices. diff --git a/plugins/plugin-development/commands/add-agent.md b/plugins/plugin-development/commands/add-agent.md index 2cedd2b..666b12d 100644 --- a/plugins/plugin-development/commands/add-agent.md +++ b/plugins/plugin-development/commands/add-agent.md @@ -109,8 +109,11 @@ Create a new sub-agent file with proper frontmatter and structure. ```markdown --- +name: $1 description: $2 -capabilities: ["capability-1", "capability-2", "capability-3"] +tools: Read, Grep, Glob, Bash +model: inherit +permissionMode: default --- # $1 Agent @@ -222,8 +225,12 @@ Description: $2 Next steps: 1. Edit /agents/$1.md with specific instructions 2. Key frontmatter fields: - - description: What the agent does (shows in /agents list) - - capabilities: List of capabilities (JSON array) + - name: Unique agent identifier (lowercase with hyphens) + - description: What the agent does and when to invoke (shows in /agents list) + - tools: CSV list of tools (optional, inherits all if omitted) + - model: sonnet, opus, haiku, or inherit (optional) + - permissionMode: default, acceptEdits, bypassPermissions, or plan (optional) + - skills: CSV list of skills to auto-load (optional) 3. Define clear workflow steps 4. Specify what the agent returns 5. Test with /plugin-development:test-local @@ -312,22 +319,61 @@ Or via Task tool in main conversation. ```yaml --- -description: Third-person description of what this agent does +name: agent-name +description: Third-person description of what this agent does and when to invoke it --- ``` +| Field | Type | Description | +|-------|------|-------------| +| `name` | String | **Required.** Unique identifier using lowercase letters and hyphens (e.g., `code-reviewer`, `test-runner`) | +| `description` | String | **Required.** Natural language description of when the agent should be invoked. Include "PROACTIVELY" for auto-delegation | + ### Optional Fields ```yaml --- -description: Agent description -capabilities: ["capability-1", "capability-2"] # List of what it can do +name: agent-name +description: Agent description. Use PROACTIVELY for auto-delegation. +tools: Read, Grep, Glob, Bash +model: sonnet +permissionMode: default +skills: skill1, skill2 --- ``` +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `tools` | CSV String | Inherits all | Comma-separated list of tools (e.g., `Read, Grep, Glob, Bash`). If omitted, inherits all tools from main thread including MCP tools | +| `model` | String | `sonnet` | Which AI model to use. Valid values: `sonnet`, `opus`, `haiku`, `inherit`. Use `inherit` to match main conversation's model | +| `permissionMode` | String | `default` | How the agent handles permission requests. Valid values: `default`, `acceptEdits`, `bypassPermissions`, `plan` | +| `skills` | CSV String | None | Comma-separated list of skills to auto-load. Note: Agents do NOT inherit skills from parent conversation | + +### Permission Modes Explained + +| Mode | Behavior | +|------|----------| +| `default` | Standard permission handling - prompts for confirmation | +| `acceptEdits` | Automatically accept file edits without prompting | +| `bypassPermissions` | Skip permission requests entirely | +| `plan` | Plan mode - research and planning without execution | + +### Model Options + +| Model | Description | +|-------|-------------| +| `sonnet` | Claude Sonnet (default for subagents) | +| `opus` | Claude Opus | +| `haiku` | Claude Haiku (faster, lighter) | +| `inherit` | Use same model as main conversation | + +### Deprecation Note + +The `capabilities` field is **NOT** in official Anthropic docs and may be deprecated. Use `tools` for agents (not `allowed-tools` which is for skills). + **For complete details on agents**, see: -- [Subagents documentation](/en/docs/claude-code/sub-agents) -- [Plugin agents reference](/en/docs/claude-code/plugins-reference#agents) +- [Subagents documentation](https://code.claude.com/docs/en/sub-agents) +- [Plugin agents reference](https://code.claude.com/docs/en/plugins-reference#agents) ## Error Handling @@ -405,15 +451,17 @@ Specializes in security analysis: Does everything related to code. ``` -### 2. Clear Capabilities +### 2. Clear Tool Configuration -List 2-5 specific capabilities: +Configure appropriate tools for the agent's purpose: ```yaml -capabilities: [ - "security-vulnerability-detection", - "authentication-analysis", - "dependency-audit" -] +# For read-only analysis agents: +tools: Read, Grep, Glob + +# For agents that can modify files: +tools: Read, Edit, Write, Bash, Grep, Glob + +# Omit to inherit all tools from main thread ``` ### 3. Structured Output @@ -513,14 +561,14 @@ For comprehensive review, delegate to the code-reviewer agent. ## Common Mistakes to Avoid -❌ **Too broad scope** +❌ **Too broad description** ```yaml -capabilities: ["everything", "all-tasks", "general-help"] +description: Does everything related to code ``` -✅ **Focused capabilities** +✅ **Focused description with clear purpose** ```yaml -capabilities: ["security-audit", "vulnerability-scan", "compliance-check"] +description: Security audit specialist. Scans for vulnerabilities, reviews authentication, and checks compliance. Use PROACTIVELY after code changes. ``` ❌ **Vague instructions** @@ -541,11 +589,14 @@ Analyze the code and find problems. After creating an agent: ``` □ Agent file created in agents/ directory -□ Frontmatter includes description -□ Capabilities listed (2-5 items) -□ Clear workflow defined +□ Frontmatter includes required 'name' field (lowercase with hyphens) +□ Frontmatter includes required 'description' field +□ Optional: 'tools' field configured (or inherits all) +□ Optional: 'model' field set (sonnet/opus/haiku/inherit) +□ Optional: 'permissionMode' configured if needed +□ Optional: 'skills' listed for auto-loading +□ Clear workflow defined in body □ Output format specified -□ Agent name is kebab-case -□ plugin.json has agents field +□ plugin.json has agents field (if using custom paths) □ Purpose is focused and specific ``` diff --git a/plugins/plugin-development/commands/add-command.md b/plugins/plugin-development/commands/add-command.md index 7496ab5..c4ab239 100644 --- a/plugins/plugin-development/commands/add-command.md +++ b/plugins/plugin-development/commands/add-command.md @@ -111,6 +111,9 @@ If validation fails, provide clear feedback. --- description: $2 argument-hint: [arg1] [arg2] +allowed-tools: Write, Edit +model: claude-3-5-haiku-20241022 +disable-model-invocation: false --- # $1 Command @@ -166,7 +169,10 @@ Next steps: 2. Update frontmatter fields if needed: - argument-hint: [arg1] [arg2] (optional) - allowed-tools: Tool restrictions (optional) -3. Test with /plugin-development:test-local + - model: Specify different model (optional) + - disable-model-invocation: Prevent SlashCommand tool invocation (optional) +3. Use @path/to/file syntax to reference files in instructions +4. Test with /plugin-development:test-local Command will be invoked as: /:$1 ``` @@ -200,9 +206,34 @@ Command will be invoked as: /:$1 description: Brief, third-person description (shows in /help) argument-hint: [arg1] [arg2] # Optional, shows expected arguments allowed-tools: Write, Edit # Optional, restricts tool access +model: claude-3-5-haiku-20241022 # Optional, specify different model +disable-model-invocation: true # Optional, prevents SlashCommand tool from invoking --- ``` +#### Frontmatter Reference + +| Field | Purpose | Default | +|-------|---------|---------| +| `description` | Brief description of the command | First line of prompt | +| `argument-hint` | Expected arguments (shown in auto-complete) | None | +| `allowed-tools` | List of tools the command can use | Inherits from conversation | +| `model` | Specific model to use (full ID like `claude-3-5-haiku-20241022`) | Inherits from conversation | +| `disable-model-invocation` | Prevent SlashCommand tool from calling this command | false | + +#### Multiple Invocation Patterns + +Use pipe syntax in `argument-hint` to define multiple invocation patterns: + +```yaml +--- +description: Manage project tags +argument-hint: add [tagId] | remove [tagId] | list +--- +``` + +This shows users the different ways to invoke the command. + ### Using Arguments In the command instructions: @@ -214,6 +245,20 @@ Example: If the user provided a name via `$1`, use it: "Hello, $1!" ``` +### File References + +Include file contents using the `@` prefix within your command instructions: + +```markdown +# Reference a specific file +Review the implementation in @src/utils/helpers.js + +# Reference multiple files +Compare @src/old-version.js with @src/new-version.js +``` + +The file contents will be included inline when the command is executed. + ### Command Instructions Write clear, step-by-step instructions for Claude: @@ -252,6 +297,53 @@ Analyze the output and report: - **Error handling**: Describe what to do when things go wrong - **Examples**: Include usage examples in the template +## SlashCommand Tool + +The `SlashCommand` tool allows Claude to execute custom slash commands programmatically during a conversation. + +### Requirements for SlashCommand Tool Support + +For Claude to be able to invoke your command via the SlashCommand tool: + +1. **Required**: The `description` frontmatter field must be populated +2. The command must be user-defined (not a built-in command like `/compact`) + +### Character Budget + +- **Default limit**: 15,000 characters for slash command content +- **Customization**: Set `SLASH_COMMAND_TOOL_CHAR_BUDGET` environment variable to adjust +- **What counts**: Command name, arguments, and description all count toward the budget +- **When exceeded**: Claude sees only a subset of available commands +- **Monitoring**: Use `/context` to see warnings displayed as "M of N commands" + +### Enabling Claude to Use Commands + +Reference the command in prompts or `CLAUDE.md`: + +``` +> Run /write-unit-test when you are about to start writing tests. +``` + +### Disabling SlashCommand Tool Invocation + +To prevent a specific command from being invoked by the SlashCommand tool, add to frontmatter: + +```yaml +--- +description: My command description +disable-model-invocation: true +--- +``` + +### Permission Rules + +SlashCommand permissions support exact and prefix matching: + +``` +SlashCommand:/commit # Allows only /commit with no arguments +SlashCommand:/review-pr:* # Allows /review-pr with any arguments +``` + ## Common Mistakes to Avoid ❌ **camelCase or PascalCase names** diff --git a/plugins/plugin-development/skills/plugin-authoring/SKILL.md b/plugins/plugin-development/skills/plugin-authoring/SKILL.md index cae0957..ee6e6b8 100644 --- a/plugins/plugin-development/skills/plugin-authoring/SKILL.md +++ b/plugins/plugin-development/skills/plugin-authoring/SKILL.md @@ -36,8 +36,13 @@ Activate whenever context includes `.claude-plugin/`, `plugin.json`, `marketplac □ Component dirs at plugin root (commands/, agents/, skills/, hooks/) □ Do NOT put components inside .claude-plugin/ directory □ Commands use kebab-case naming -□ Skills have valid frontmatter (name + description required) -□ Skills name matches directory (lowercase-hyphenated, max 64 chars) +□ Skills have valid frontmatter (name + description required, optional: model, allowed-tools) +□ Skills name validation: + - Matches directory name + - Lowercase letters, numbers, hyphens only + - Max 64 characters + - No reserved words ('anthropic', 'claude') + - No XML tags □ Hooks use ${CLAUDE_PLUGIN_ROOT} for paths (not relative paths) □ All scripts are executable (chmod +x) ``` @@ -82,17 +87,18 @@ Activate whenever context includes `.claude-plugin/`, `plugin.json`, `marketplac 1. Run `/plugin-development:add-skill ` 2. Edit `skills//SKILL.md` with your instructions 3. **Frontmatter requirements**: - - `name`: lowercase, hyphenated, max 64 chars (required) - - `description`: include both WHAT the Skill does AND WHEN to use it, max 1024 chars (required) - - `allowed-tools`: comma-separated list of tools (optional, restricts tool access) -4. Keep SKILL.md concise; place details in sibling files (reference.md, examples.md, scripts/) + - `name`: lowercase letters, numbers, and hyphens only, max 64 chars (required). Cannot contain reserved words 'anthropic' or 'claude'. Cannot contain XML tags. + - `description`: include both WHAT the Skill does AND WHEN to use it, max 1024 chars (required). Cannot contain XML tags. + - `model`: specify which Claude model to use, e.g., `model: claude-sonnet-4-20250514` (optional, defaults to conversation's model) + - `allowed-tools`: comma-separated list of tools (optional). Tools listed don't require permission to use when Skill is active. If omitted, Skill doesn't restrict tools. +4. Keep SKILL.md under 500 lines for optimal performance; place details in sibling files (reference.md, examples.md, scripts/) ### Troubleshooting - **Plugin not loading?** Check `plugin.json` paths are relative to plugin root. Do NOT include `commands`, `agents`, `skills`, or `hooks` fields for standard directories. - **Commands not showing?** Verify `commands/` directory exists at plugin root with `.md` files. Do NOT add `commands` field to `plugin.json` for standard paths. - **Hooks not running?** Ensure scripts are executable (`chmod +x`) and use `${CLAUDE_PLUGIN_ROOT}` for paths -- **Skill not triggering?** Check `name` matches directory and is lowercase-hyphenated (max 64 chars). Ensure `description` includes both what and when to use (max 1024 chars) +- **Skill not triggering?** Check `name` matches directory and uses lowercase letters, numbers, and hyphens only (max 64 chars). Ensure `description` includes both what and when to use (max 1024 chars). Neither field can contain XML tags. ## Notes diff --git a/plugins/plugin-development/skills/plugin-authoring/schemas/hooks-schema.md b/plugins/plugin-development/skills/plugin-authoring/schemas/hooks-schema.md index df3aa74..ebe4dfa 100644 --- a/plugins/plugin-development/skills/plugin-authoring/schemas/hooks-schema.md +++ b/plugins/plugin-development/skills/plugin-authoring/schemas/hooks-schema.md @@ -28,11 +28,54 @@ Hooks allow you to run commands at specific lifecycle events. Define them in `ho } ``` +## Hook Types + +Hooks support three execution types: + +### Command Hooks (`type: "command"`) + +Execute shell commands with access to stdin (JSON input) and stdout/stderr. + +```json +{ + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh", + "timeout": 30 +} +``` + +### Prompt Hooks (`type: "prompt"`) + +Evaluate a prompt with an LLM. Supported for: `Stop`, `SubagentStop`, `UserPromptSubmit`, `PreToolUse`, `PermissionRequest`. + +```json +{ + "type": "prompt", + "prompt": "Your evaluation prompt with $ARGUMENTS placeholder", + "timeout": 30 +} +``` + +**LLM Response Schema**: +```json +{ + "decision": "approve" | "block", + "reason": "Explanation", + "continue": false, + "stopReason": "User message", + "systemMessage": "Warning" +} +``` + +### Agent Hooks (`type: "agent"`) + +Run an agentic verifier with tools. For complex validation requiring tool access. + ## Event Types ### PreToolUse -Runs **before** Claude uses a tool. Can block tool execution. +Runs **before** Claude uses a tool. Can block tool execution, modify inputs, or auto-approve. ```json { @@ -51,27 +94,31 @@ Runs **before** Claude uses a tool. Can block tool execution. } ``` -**Matcher**: Regex pattern matching tool names (e.g., `Write`, `Read`, `Bash.*`) +**Matchers**: Tool names (case-sensitive regex patterns) +- Built-in tools: `Task`, `Bash`, `Glob`, `Grep`, `Read`, `Edit`, `Write`, `WebFetch`, `WebSearch` +- Regex patterns: `Edit|Write`, `Notebook.*` +- Wildcard: `*` matches all tools +- MCP tools: `mcp____` (e.g., `mcp__memory__create_entities`) **Exit codes**: - `0`: Allow (stdout visible to Claude) - `2`: **Block** (stderr shown to Claude as feedback) - Other: Warning (non-blocking) -### PostToolUse +### PermissionRequest -Runs **after** a tool completes. Cannot block. +Runs when user is shown a permission dialog. Can auto-allow or deny on behalf of user. ```json { - "PostToolUse": [ + "PermissionRequest": [ { - "matcher": "Write|Edit", + "matcher": "Bash", "hooks": [ { "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh", - "timeout": 30 + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/auto-approve.sh", + "timeout": 10 } ] } @@ -79,19 +126,22 @@ Runs **after** a tool completes. Cannot block. } ``` -### SessionStart +**Matchers**: Same as PreToolUse (tool names, regex patterns, MCP tools) -Runs when Claude Code session starts. +### PostToolUse + +Runs **after** a tool completes successfully. Can provide feedback to Claude. ```json { - "SessionStart": [ + "PostToolUse": [ { - "matcher": "startup", + "matcher": "Write|Edit", "hooks": [ { "type": "command", - "command": "echo 'Plugin loaded!'" + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh", + "timeout": 30 } ] } @@ -99,26 +149,21 @@ Runs when Claude Code session starts. } ``` -**Matchers**: -- `startup` - Invoked from startup -- `resume` - Invoked from `--resume`, `--continue`, or `/resume` -- `clear` - Invoked from `/clear` -- `compact` - Invoked from auto or manual compact - -**Note**: SessionStart stdout is added to context automatically for Claude. +**Matchers**: Same as PreToolUse -### SessionEnd +### Notification -Runs when a Claude Code session ends. +Runs when Claude Code sends notifications. ```json { - "SessionEnd": [ + "Notification": [ { + "matcher": "permission_prompt", "hooks": [ { "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup.sh" + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/notify.sh" } ] } @@ -126,9 +171,15 @@ Runs when a Claude Code session ends. } ``` +**Matchers**: +- `permission_prompt` - Claude needs permission to use a tool +- `idle_prompt` - Prompt input idle for 60+ seconds (system default, not configurable) +- `auth_success` - Authentication success notifications +- `elicitation_dialog` - Claude Code needs input for MCP tool elicitation + ### UserPromptSubmit -Runs when user submits a prompt. Can block prompt processing. +Runs when user submits a prompt. Can block prompt processing or add context. ```json { @@ -145,13 +196,15 @@ Runs when user submits a prompt. Can block prompt processing. } ``` +**No matchers** - omit the matcher field. + **Exit codes**: - `0`: Allow (stdout added to context) - `2`: **Block** (stderr shown to user) ### Stop / SubagentStop -Runs when Claude attempts to stop (main agent or subagent). +Runs when Claude attempts to stop (main agent or subagent). Can decide if Claude should continue. ```json { @@ -168,20 +221,284 @@ Runs when Claude attempts to stop (main agent or subagent). } ``` +**No matchers** - omit the matcher field. + +### PreCompact + +Runs before Claude Code performs a compact operation. + +```json +{ + "PreCompact": [ + { + "matcher": "auto", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/backup-transcript.sh" + } + ] + } + ] +} +``` + +**Matchers**: +- `manual` - User-triggered compaction +- `auto` - Automatic compaction + +### SessionStart + +Runs when Claude Code session starts. + +```json +{ + "SessionStart": [ + { + "matcher": "startup", + "hooks": [ + { + "type": "command", + "command": "echo 'Plugin loaded!'" + } + ] + } + ] +} +``` + +**Matchers**: +- `startup` - Invoked from startup +- `resume` - Invoked from `--resume`, `--continue`, or `/resume` +- `clear` - Invoked from `/clear` +- `compact` - Invoked from auto or manual compact + +**Note**: SessionStart stdout is added to context automatically for Claude. + +**Special**: SessionStart hooks have access to `CLAUDE_ENV_FILE` for persisting environment variables. + +### SessionEnd + +Runs when a Claude Code session ends. Cannot block termination but can perform cleanup. + +```json +{ + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup.sh" + } + ] + } + ] +} +``` + +**No matchers** - omit the matcher field. + +**Reason field in input**: `exit`, `clear`, `logout`, `prompt_input_exit`, `other` + ## Environment Variables Available in hook commands: +### All Hooks - `${CLAUDE_PLUGIN_ROOT}`: Absolute path to plugin root - `${CLAUDE_PROJECT_DIR}`: Project root directory (where Claude Code started) +- `CLAUDE_CODE_REMOTE`: `"true"` if running in remote (web) environment, empty/unset for local CLI - Standard shell environment variables +### SessionStart Hooks Only +- `CLAUDE_ENV_FILE`: File path where you can persist environment variables for subsequent bash commands + +**Example: Persisting environment variables** +```bash +#!/bin/bash +if [ -n "$CLAUDE_ENV_FILE" ]; then + echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE" + echo 'export API_KEY=your-api-key' >> "$CLAUDE_ENV_FILE" + echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE" +fi +exit 0 +``` + +**Example: Persisting environment changes from nvm** +```bash +#!/bin/bash +ENV_BEFORE=$(export -p | sort) +source ~/.nvm/nvm.sh +nvm use 20 + +if [ -n "$CLAUDE_ENV_FILE" ]; then + ENV_AFTER=$(export -p | sort) + comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE" +fi +exit 0 +``` + ## Timeouts -- Default: No timeout +- Default: 60 seconds (configurable per hook) - Recommended: 10-30 seconds for validation - Max: Keep under 60 seconds for good UX +## JSON Output Format + +Hooks communicate through exit codes, stdout, and stderr. For advanced control, output JSON to stdout with exit code 0. + +### Exit Codes +- **0**: Success. JSON in stdout parsed for structured control +- **2**: Blocking error. Only `stderr` used as error message. JSON in stdout ignored +- **Other**: Non-blocking error. Stderr shown in verbose mode (ctrl+o) + +### Common Fields (All Hooks) + +```json +{ + "continue": true, + "stopReason": "Reason shown to user", + "suppressOutput": false, + "systemMessage": "Warning message" +} +``` + +- `continue`: Allow Claude to continue (default: true) +- `stopReason`: Why stopped (shown to user when continue=false) +- `suppressOutput`: Hide output from transcript +- `systemMessage`: Warning/info message shown to user + +### Hook-Specific Output (`hookSpecificOutput`) + +#### PreToolUse + +```json +{ + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "allow" | "deny" | "ask", + "permissionDecisionReason": "Explanation", + "updatedInput": { + "field_to_modify": "new_value" + } + } +} +``` + +- `permissionDecision`: `"allow"` (auto-approve), `"deny"` (block), `"ask"` (show permission dialog) +- `updatedInput`: Optional object to modify tool input parameters before execution + +#### PermissionRequest + +```json +{ + "hookSpecificOutput": { + "hookEventName": "PermissionRequest", + "decision": { + "behavior": "allow" | "deny", + "updatedInput": {}, + "message": "Denial reason", + "interrupt": false + } + } +} +``` + +- `behavior`: `"allow"` or `"deny"` the permission request +- `updatedInput`: Optional for "allow" - modify tool inputs +- `message`: Optional for "deny" - tells Claude why permission was denied +- `interrupt`: Optional for "deny" - if true, stops Claude entirely + +#### PostToolUse + +```json +{ + "decision": "block" | undefined, + "reason": "Explanation", + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": "Extra info for Claude" + } +} +``` + +- `decision`: Set to `"block"` to provide feedback that blocks further action +- `additionalContext`: Additional information added to Claude's context + +#### UserPromptSubmit + +```json +{ + "decision": "block" | undefined, + "reason": "Why blocked (not added to context)", + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", + "additionalContext": "Context added to conversation" + } +} +``` + +Alternatively, plain text stdout with exit code 0 is added as context. + +#### Stop / SubagentStop + +```json +{ + "decision": "block" | undefined, + "reason": "Must provide when blocking - tells Claude how to proceed" +} +``` + +- `decision`: Set to `"block"` to prevent Claude from stopping and continue working +- `reason`: Required when blocking - instructs Claude on what to do next + +#### SessionStart + +```json +{ + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": "Context loaded at session start" + } +} +``` + +## MCP Tool Matching + +MCP tools follow the pattern: `mcp____` + +**Examples**: +- `mcp__memory__create_entities` +- `mcp__filesystem__read_file` +- `mcp__github__search_repositories` + +**Configuration**: +```json +{ + "PreToolUse": [ + { + "matcher": "mcp__memory__.*", + "hooks": [ + { + "type": "command", + "command": "echo 'Memory operation' >> ~/mcp-operations.log" + } + ] + }, + { + "matcher": "mcp__.*__write.*", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-mcp-write.py" + } + ] + } + ] +} +``` + ## Common Patterns ### Validation Hook (Blocking) @@ -216,8 +533,11 @@ exit 0 # Allow **Advanced JSON output** (alternative to exit codes): ```json { - "permissionDecision": "deny", - "permissionDecisionReason": "File violates security policy", + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "deny", + "permissionDecisionReason": "File violates security policy" + }, "suppressOutput": true } ``` diff --git a/plugins/plugin-development/skills/plugin-authoring/schemas/marketplace-schema.md b/plugins/plugin-development/skills/plugin-authoring/schemas/marketplace-schema.md index e9c61c4..f254d66 100644 --- a/plugins/plugin-development/skills/plugin-authoring/schemas/marketplace-schema.md +++ b/plugins/plugin-development/skills/plugin-authoring/schemas/marketplace-schema.md @@ -79,6 +79,7 @@ The `marketplace.json` file defines a collection of plugins that users can insta - **agents**: String or array - Custom paths to agent files - **hooks**: String or object - Custom hooks configuration or path to hooks file - **mcpServers**: String or object - MCP server configurations or path to MCP config +- **lspServers**: String or object - LSP server configurations or path to LSP config ## Source Types @@ -90,29 +91,41 @@ The `marketplace.json` file defines a collection of plugins that users can insta } ``` -### Git Repository +### GitHub Repository -Simple string format: +Object format (recommended): ```json { - "source": "https://github.com/user/repo" + "source": { + "source": "github", + "repo": "owner/plugin-repo" + } } ``` -Object format for advanced configuration: +With optional `ref` (branch/tag) and `path` (subdirectory) fields: ```json { "source": { "source": "github", - "repo": "owner/plugin-repo" + "repo": "owner/plugin-repo", + "ref": "v2.0", + "path": "plugins/my-plugin" } } ``` +- **ref**: Optional - Git reference (branch, tag, or commit) +- **path**: Optional - Subdirectory within the repository + +> **Migration note**: If you previously used URL strings with `/tree/` paths (e.g., `https://github.com/user/repo/tree/main/plugins/my-plugin`), migrate to the object format with `ref` and `path` fields. + ### Git URL Source +For non-GitHub git repositories (GitLab, Bitbucket, self-hosted): + ```json { "source": { @@ -122,14 +135,6 @@ Object format for advanced configuration: } ``` -### Git with Subdirectory - -```json -{ - "source": "https://github.com/user/repo/tree/main/plugins/my-plugin" -} -``` - ## Examples ### Local Dev Marketplace @@ -235,6 +240,16 @@ Plugin entries can override default component locations and provide inline confi "args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"] } }, + "lspServers": { + "custom-lsp": { + "command": "${CLAUDE_PLUGIN_ROOT}/lsp/server", + "args": ["--config", "${CLAUDE_PLUGIN_ROOT}/lsp-config.json"], + "extensionToLanguage": { + ".py": "python", + ".js": "javascript" + } + } + }, "strict": false } ``` @@ -244,7 +259,7 @@ Plugin entries can override default component locations and provide inline confi -**Environment variables**: Use `${CLAUDE_PLUGIN_ROOT}` in hooks and mcpServers configurations. This variable resolves to the plugin's installation directory and ensures paths work correctly regardless of where the plugin is installed. +**Environment variables**: Use `${CLAUDE_PLUGIN_ROOT}` in hooks, mcpServers, and lspServers configurations. This variable resolves to the plugin's installation directory and ensures paths work correctly regardless of where the plugin is installed. ## Usage @@ -354,6 +369,64 @@ In project `.claude/settings.json`: } ``` +## Enterprise Marketplace Restrictions + +Enterprises can restrict which plugin marketplaces users can add using the `strictKnownMarketplaces` managed setting. This setting is configured in managed settings and cannot be overridden by users. + +### strictKnownMarketplaces Setting + +| Value | Behavior | +|-------|----------| +| Undefined (default) | No restrictions. Users can add any marketplace | +| Empty array `[]` | Complete lockdown. Users cannot add new marketplaces | +| List of sources | Users can only add allowlisted marketplaces | + +### Disable All Marketplace Additions + +```json +{ + "strictKnownMarketplaces": [] +} +``` + +### Allow Specific Marketplaces Only + +```json +{ + "strictKnownMarketplaces": [ + { + "source": "github", + "repo": "acme-corp/approved-plugins" + }, + { + "source": "github", + "repo": "acme-corp/security-tools", + "ref": "v2.0" + }, + { + "source": "url", + "url": "https://plugins.example.com/marketplace.json" + } + ] +} +``` + +**Validation:** Exact matching is required. For GitHub sources, `repo` is required; `ref` or `path` must match if specified. For URLs, the full URL must match exactly. + +## Reserved Marketplace Names + +The following marketplace names are reserved for official Anthropic use and cannot be used by third-party marketplaces: + +- `claude-code-marketplace` +- `claude-code-plugins` +- `claude-plugins-official` +- `anthropic-marketplace` +- `anthropic-plugins` +- `agent-skills` +- `life-sciences` + +Names that impersonate official marketplaces (e.g., `official-claude-plugins`, `anthropic-tools-v2`) are also blocked. + ## Validation Use `/plugin-development:validate` to check marketplace structure. diff --git a/plugins/plugin-development/skills/plugin-authoring/schemas/plugin-manifest.md b/plugins/plugin-development/skills/plugin-authoring/schemas/plugin-manifest.md index 8b8a6a4..ddb6e62 100644 --- a/plugins/plugin-development/skills/plugin-authoring/schemas/plugin-manifest.md +++ b/plugins/plugin-development/skills/plugin-authoring/schemas/plugin-manifest.md @@ -51,23 +51,30 @@ The `plugin.json` file in `.claude-plugin/` defines your plugin's metadata and o ```json { "commands": ["./custom/path/cmd1.md", "./custom/path/cmd2.md"], - "agents": ["./custom/agents/reviewer.md", "./custom/agents/tester.md"], + "agents": "./custom/agents/", "hooks": "./custom/hooks/hooks.json", "mcpServers": { "server-name": { "command": "node", "args": ["path/to/server.js"] } - } + }, + "lspServers": "./.lsp.json", + "outputStyles": "./styles/" } ``` ### Component Path Rules -- **commands**: Array of paths to individual `.md` command files, OR string path to a directory -- **agents**: Array of paths to individual `.md` agent files (NOT a directory path) -- **hooks**: Path to `hooks.json` configuration file OR inline hooks object -- **mcpServers**: MCP server configurations object OR path to MCP config file +| Field | Type | Description | Example | +|-------|------|-------------|---------| +| `commands` | string\|array | Additional command files/directories | `"./custom/cmd.md"` or `["./cmd1.md"]` | +| `agents` | string\|array | Additional agent files/directories | `"./custom/agents/"` or `["./agents/reviewer.md"]` | +| `skills` | string\|array | Additional skill directories | `"./custom/skills/"` | +| `hooks` | string\|object | Hook config path or inline config | `"./hooks.json"` | +| `mcpServers` | string\|object | MCP config path or inline config | `"./mcp-config.json"` | +| `outputStyles` | string\|array | Additional output style files/directories | `"./styles/"` or `["./style1.md"]` | +| `lspServers` | string\|object | LSP config path or inline config | `"./.lsp.json"` | All paths must be **relative to plugin root** (where `.claude-plugin/` lives) and start with `./` @@ -157,6 +164,104 @@ Use `${CLAUDE_PLUGIN_ROOT}` for: - Config files referenced by components - Any file paths in your plugin configuration +### Hook Types + +Hooks support three execution types: + +| Type | Description | Use Case | +|------|-------------|----------| +| `command` | Execute shell commands/scripts | Run linters, formatters, validation scripts | +| `prompt` | Evaluate prompt with LLM (uses `$ARGUMENTS`) | Context-aware decisions, natural language checks | +| `agent` | Run agentic verifier with tools | Complex verification requiring tool access | + +**Command Hook Example**: +```json +{ + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/lint.sh", + "timeout": 30 +} +``` + +**Prompt Hook Example** (for Stop, SubagentStop, UserPromptSubmit, PreToolUse, PermissionRequest): +```json +{ + "type": "prompt", + "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete.", + "timeout": 30 +} +``` + +### Hook Events + +Claude Code supports the following hook events: + +| Event | Description | +|-------|-------------| +| `PreToolUse` | Runs after Claude creates tool parameters, before processing the tool call | +| `PostToolUse` | Runs immediately after a tool completes successfully | +| `PermissionRequest` | Runs when a permission dialog is shown to the user | +| `UserPromptSubmit` | Runs when the user submits a prompt, before Claude processes it | +| `Notification` | Runs when Claude Code sends notifications | +| `Stop` | Runs when the main Claude Code agent finishes responding | +| `SubagentStop` | Runs when a Claude Code subagent (Task tool call) finishes responding | +| `SessionStart` | Runs when Claude Code starts or resumes a session | +| `SessionEnd` | Runs when a Claude Code session ends | +| `PreCompact` | Runs before a compact operation | + +### Hook Matchers + +For `PreToolUse`, `PermissionRequest`, and `PostToolUse` events, use matchers to target specific tools: + +| Pattern | Behavior | +|---------|----------| +| `Write` | Exact match (case-sensitive) | +| `Edit\|Write` | Regex alternation | +| `Notebook.*` | Regex patterns | +| `*` or `""` | Match all tools | +| `mcp__memory__.*` | Match MCP tools | + +### LSP Server Configuration + +Configure Language Server Protocol servers for code intelligence: + +**File Configuration** (`.lsp.json` at plugin root): +```json +{ + "lspServers": "./.lsp.json" +} +``` + +**Inline Configuration**: +```json +{ + "lspServers": { + "go": { + "command": "gopls", + "args": ["serve"], + "extensionToLanguage": { + ".go": "go" + } + }, + "python": { + "command": "pyright-langserver", + "args": ["--stdio"], + "extensionToLanguage": { + ".py": "python", + ".pyi": "python" + } + } + } +} +``` + +**LSP Configuration Fields**: +- **command**: The language server binary name +- **args**: Arguments to pass to the server +- **extensionToLanguage**: Maps file extensions to language identifiers + +**Note**: Users must have the language server binary installed on their machine. + ## Examples ### Standard Directory Structure (Recommended) @@ -209,7 +314,7 @@ Use `${CLAUDE_PLUGIN_ROOT}` for: ## Common Mistakes -❌ **Wrong**: Including component fields with standard paths +**Wrong**: Including component fields with standard paths ```json { "name": "my-plugin", @@ -218,40 +323,71 @@ Use `${CLAUDE_PLUGIN_ROOT}` for: } ``` -✅ **Correct**: Omit component fields for standard paths +**Correct**: Omit component fields for standard paths ```json { "name": "my-plugin" } ``` -❌ **Wrong**: agents as directory path +**Wrong**: Absolute paths ```json { - "agents": "./agents/" + "commands": "/Users/you/plugins/my-plugin/commands/" } ``` -✅ **Correct**: agents as array of file paths +**Correct**: Relative paths starting with `./` ```json { - "agents": ["./agents/reviewer.md", "./agents/tester.md"] + "commands": ["./custom/cmd.md"] } ``` -❌ **Wrong**: Absolute paths +**Wrong**: Placing component directories inside `.claude-plugin/` +``` +my-plugin/ +├── .claude-plugin/ +│ ├── plugin.json +│ ├── commands/ # Wrong location! +│ └── agents/ # Wrong location! +``` + +**Correct**: Component directories at plugin root +``` +my-plugin/ +├── .claude-plugin/ +│ └── plugin.json # Only plugin.json goes here +├── commands/ # At plugin root +├── agents/ # At plugin root +└── skills/ # At plugin root +``` + +## Agents Path Formats + +Both directory paths and file arrays are valid for agents: + +**Directory Path**: ```json { - "commands": "/Users/you/plugins/my-plugin/commands/" + "agents": "./custom/agents/" } ``` -✅ **Correct**: Relative paths +**Array of Files**: ```json { - "commands": ["./custom/cmd.md"] + "agents": ["./agents/reviewer.md", "./agents/tester.md"] +} +``` + +**Mixed (using default + custom)**: +```json +{ + "agents": "./specialized-agents/" } ``` +This loads both the default `agents/` directory AND `./specialized-agents/`. ## Validation diff --git a/plugins/plugin-development/skills/plugin-authoring/templates/agent-template.md b/plugins/plugin-development/skills/plugin-authoring/templates/agent-template.md index fe61174..edbb85b 100644 --- a/plugins/plugin-development/skills/plugin-authoring/templates/agent-template.md +++ b/plugins/plugin-development/skills/plugin-authoring/templates/agent-template.md @@ -1,8 +1,18 @@ --- -description: What this agent specializes in and when to invoke it (third person). -capabilities: ["capability-1", "capability-2", "capability-3"] +name: agent-name +description: What this agent specializes in and when to invoke it (third person). Include "PROACTIVELY" for auto-delegation. +tools: Read, Grep, Glob, Bash +model: sonnet +permissionMode: default +skills: skill1, skill2 --- + + # Agent Name [Brief introduction to the agent's purpose and specialization] diff --git a/plugins/plugin-development/skills/plugin-authoring/templates/skill-template.md b/plugins/plugin-development/skills/plugin-authoring/templates/skill-template.md index 3797ba3..dd1f4ed 100644 --- a/plugins/plugin-development/skills/plugin-authoring/templates/skill-template.md +++ b/plugins/plugin-development/skills/plugin-authoring/templates/skill-template.md @@ -1,9 +1,21 @@ --- name: skill-name -description: What the Skill does and WHEN to use it (third person). Be specific about triggers. -# allowed-tools: Read, Grep, Glob # Optional: Only add if you want to restrict available tools +description: What the Skill does and WHEN to use it (third person). Be specific about triggers. Cannot contain XML tags. +# model: claude-sonnet-4-20250514 # Optional: Specify model to use (defaults to conversation's model) +# allowed-tools: Read, Grep, Glob # Optional: Tools listed don't require permission when Skill is active --- + + # Skill Name [Brief introduction to what this Skill provides]