
Claude Code Sdk
- 3 installs
- 19 repo stars
- Updated August 1, 2026
- xobotyi/cc-foundry
Helps with ai & agent building tasks during AI-assisted development.
About
claude-code-sdk is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- claude-code-sdk
- AI & Agent Building
- AI-coding skill
Claude Code Sdk by the numbers
- 3 all-time installs (skills.sh)
- Ranked #13,657 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/xobotyi/cc-foundry --skill claude-code-sdkAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3 |
|---|---|
| repo stars | ★ 19 |
| Last updated | August 1, 2026 |
| Repository | xobotyi/cc-foundry ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Claude Code SDK
Authoritative reference for Claude Code extensibility and configuration. Use this skill when building, configuring, or debugging any Claude Code extension mechanism.
References
| Topic | Reference | Contents |
|---|---|---|
| Skills | [${CLAUDE_SKILL_DIR}/references/skills.md] | Frontmatter fields, invocation control matrix, string substitutions, dynamic context injection, subagent execution, nested discovery, sharing |
| Subagents | [${CLAUDE_SKILL_DIR}/references/subagents.md] | Built-in agents table, frontmatter fields, permission modes, tool control, preloading skills, persistent memory, worktree isolation, CLI-defined agents, teams |
| Plugins | [${CLAUDE_SKILL_DIR}/references/plugins.md] | Plugin manifest schema, component paths, marketplace schema, source types, strict mode, version resolution, LSP server table, caching, validation |
| Hooks | [${CLAUDE_SKILL_DIR}/references/hooks.md] | All 15 event details (input fields, output schemas, exit code behavior), matcher patterns, hook types (command/prompt/agent), async hooks, security |
| MCP | [${CLAUDE_SKILL_DIR}/references/mcp.md] | Server installation (HTTP/SSE/stdio), scopes, OAuth authentication, environment variable expansion, managed MCP config, tool search, plugin-provided servers |
| Memory | [${CLAUDE_SKILL_DIR}/references/memory.md] | CLAUDE.md hierarchy and loading, auto memory structure, import syntax, modular rules with path scoping, organization-level management |
| Model config | [${CLAUDE_SKILL_DIR}/references/model-config.md] | Model aliases, setting methods, effort levels, extended context (1M), opusplan mode, third-party provider pinning, prompt caching env vars |
| Output styles | [${CLAUDE_SKILL_DIR}/references/output-styles.md] | Built-in styles, frontmatter fields, keep-coding-instructions flag, comparison with CLAUDE.md/agents/skills |
| Settings | [${CLAUDE_SKILL_DIR}/references/settings.md] | Scope hierarchy, permission rule syntax, sandbox config, common settings table, environment variables (API, behavior, feature toggles, paths), tools list |
| Status line | [${CLAUDE_SKILL_DIR}/references/statusline.md] | Configuration, JSON input schema with all fields, ANSI colors, clickable links, caching, plugin delivery |
| Best practices | [${CLAUDE_SKILL_DIR}/references/best-practices.md] | Context management, verification patterns, explore-plan-code workflow, CLAUDE.md authoring, session management, automation/scaling |
Read the relevant reference before making detailed changes. The rules below cover the decision framework; references provide field-level schemas and implementation details.
Concepts
<concepts> Skill — Prompt template in SKILL.md that extends Claude's capabilities. Loaded on-demand when description matches user request. Can include references/ for detailed content. Invoked with /skill-name or automatically.
Plugin — Distributable package containing skills, hooks, MCP servers, LSP servers, output styles, and default settings. Has optional .claude-plugin/plugin.json manifest. Installed from marketplace or local path. Skills namespaced as /plugin:skill.
Hook — Deterministic automation triggered at 15 lifecycle events (tool use, session start/end, permission request, subagent lifecycle, teammate/task events). Three types: command (shell), prompt (LLM decision), agent (multi-turn verification). Configured in settings, plugin, or frontmatter.
MCP Server — External tool/resource provider via Model Context Protocol. Connects Claude to databases, APIs, services. Supports stdio, HTTP, SSE transports and OAuth authentication. Configured per-project, per-user, or via plugin.
Output Style — Persona/behavior modifier via system prompt changes. Affects how Claude responds without changing capabilities. Built-in: Default, Explanatory, Learning.
CLAUDE.md — Project memory file providing persistent context about codebase, conventions, instructions. Hierarchy: managed > user > project. Loaded automatically at session start. Auto memory (MEMORY.md) stores Claude's own learnings per project.
Subagent — Isolated context for delegated tasks. Built-in types: Explore (read-only), Plan (architecture), general-purpose. Custom agents in .claude/agents/. Supports persistent memory, worktree isolation. Agent teams coordinate multiple subagents across sessions.
Settings — Configuration hierarchy controlling permissions, model, hooks, behavior. Scopes: managed > user > project > local. </concepts>
Choosing the Right Extension Mechanism
Use these rules when deciding how to extend Claude Code. Each mechanism serves a different purpose; choosing wrong causes friction or failure.
Skills vs Subagents vs Hooks vs MCP vs CLAUDE.md
- Use CLAUDE.md for persistent project context that applies to every session:
coding conventions, repo structure, build commands, team practices. It loads automatically — no invocation needed. Keep it concise; bloated CLAUDE.md causes instruction drift.
- Use skills for reusable domain expertise or workflows that load on-demand.
Skills load only when relevant, keeping context clean when not needed. Two content patterns:
- Reference content — knowledge Claude applies alongside conversation
(conventions, patterns, style guides). Runs inline, auto-triggered.
- Task content — step-by-step actions (deploy, commit, generate). Runs
in subagent (context: fork), manual invocation (disable-model-invocation: true).
- Use subagents for isolated delegated work with tool restrictions or when
output is verbose and should not consume main context. Custom agents in .claude/agents/ get their own system prompt, tool set, and permissions. Subagents cannot spawn other subagents.
- Use hooks for deterministic automation that must always happen — formatting
after edits, blocking writes to protected paths, injecting context at session start. Unlike CLAUDE.md instructions (advisory), hooks are guaranteed to run.
- Use MCP servers for connecting to external services: databases, APIs, issue
trackers. MCP is the integration layer — use it when Claude needs tools or resources from outside the local environment.
- Use output styles when you need to change how Claude communicates (tone,
format, persona) without changing its capabilities. Styles modify the system prompt and are always active once selected.
- Use plugins to package and distribute any combination of the above as a
single installable unit.
Skill Content Design
When creating a skill, the content pattern determines frontmatter:
| Pattern | context | disable-model-invocation | Typical trigger |
|---|---|---|---|
| Reference content (conventions, patterns) | (inline) | false | Auto or manual |
| Task content (deploy, generate, commit) | fork | true | Manual only |
Reference content runs inline so Claude uses it alongside conversation context. Task content runs in a subagent — the skill content becomes the subagent's prompt, and it has no access to conversation history.
Skill Invocation Control
| Frontmatter | User invokes | Claude invokes | Context load |
|---|---|---|---|
| (default) | Yes | Yes | Description always; full skill when invoked |
disable-model-invocation: true | Yes | No | Neither description nor full skill |
user-invocable: false | No | Yes | Description always; full skill when invoked |
user-invocable: false hides from / menu but does not block the Skill tool. To block programmatic invocation entirely, use disable-model-invocation: true.
Skill descriptions have a character budget: 2% of context window (fallback 16,000 chars). Run /context to check for excluded skills.
Subagent Selection
| Need | Solution |
|---|---|
| Read-only codebase exploration | Built-in Explore agent |
| Plan mode research | Built-in Plan agent |
| Complex multi-step task with tools | Built-in general-purpose agent |
| Specialized role with custom system prompt | Custom agent in .claude/agents/ |
| Skill that runs in isolation | Skill with context: fork + agent field |
Skills with context: fork write the task in the skill and pick an agent type. Custom subagents get their own system prompt and load skills as reference content. Use custom subagents when the agent needs a persistent identity, tool restrictions, or persistent memory across sessions.
Hook Type Selection
| Type | Use when | Timeout |
|---|---|---|
command | Deterministic check (lint, validate, format) | 600s |
prompt | LLM judgment on hook input data alone | 30s |
agent | LLM judgment that needs file inspection or commands | 60s |
Command hooks are the default. Use prompt hooks when the decision requires understanding intent (not just pattern matching). Use agent hooks when verification requires reading files or running commands.
All matching hooks run in parallel. Exit code 2 blocks the operation (for blocking events). Always check stop_hook_active in Stop hooks to prevent infinite loops.
Settings Scope Selection
| Need | Scope | Location |
|---|---|---|
| Organization policy (cannot override) | Managed | System paths |
| Personal preferences across projects | User | ~/.claude/settings.json |
| Team-shared project config | Project | .claude/settings.json |
| Personal project-specific config | Local | .claude/settings.local.json |
Precedence: managed > CLI args > local > project > user. Permission evaluation order: deny > ask > allow (first match wins).
Quick Reference
Skill Locations
| Scope | Path |
|---|---|
| Enterprise | Managed settings |
| Personal | ~/.claude/skills/<name>/SKILL.md |
| Project | .claude/skills/<name>/SKILL.md |
| Plugin | <plugin>/skills/<name>/SKILL.md |
Plugin Layout
plugin-name/
├── .claude-plugin/
│ └── plugin.json # Manifest (optional)
├── skills/
│ └── skill-name/
│ ├── SKILL.md
│ └── references/
├── agents/ # Custom subagents
├── hooks/
│ └── hooks.json
├── output-styles/
├── settings.json # Default settings (agent key only)
├── .mcp.json
├── .lsp.json
└── README.mdHook Events (15)
| Event | When | Can Block |
|---|---|---|
SessionStart | Session begins/resumes | No |
UserPromptSubmit | Before prompt processing | Yes |
PreToolUse | Before tool executes | Yes |
PermissionRequest | Permission dialog shown | Yes |
PostToolUse | After tool success | No |
PostToolUseFailure | After tool failure | No |
Notification | Notification sent | No |
SubagentStart | Subagent spawned | No |
SubagentStop | Subagent finishes | Yes |
Stop | Claude finishes responding | Yes |
TeammateIdle | Teammate going idle | Yes |
TaskCompleted | Task marked complete | Yes |
ConfigChange | Config file changes | Yes |
PreCompact | Before compaction | No |
SessionEnd | Session terminates | No |
Settings Scopes
| Scope | Location | Shared |
|---|---|---|
| Managed | System path | Org-wide |
| User | ~/.claude/settings.json | No |
| Project | .claude/settings.json | Git |
| Local | .claude/settings.local.json | No |
Memory Hierarchy
| Type | Location | Shared |
|---|---|---|
| Managed policy | System paths | Org-wide |
| User memory | ~/.claude/CLAUDE.md | Personal, all projects |
| Project memory | ./CLAUDE.md or .claude/CLAUDE.md | Team via VCS |
| Project rules | .claude/rules/*.md | Team via VCS |
| Local memory | ./CLAUDE.local.md | Personal, this project |
| Auto memory | ~/.claude/projects/<project>/memory/ | Personal, per project |
More specific memory takes precedence. CLAUDE.md in parent directories loads automatically; child directories load on demand when working in those paths.
Cross-Skill Dependencies
When building Claude Code extensions, invoke specialized skills for component design:
- Skills — invoke
ai-helpers:skill-engineeringfor SKILL.md design - Subagents — invoke
ai-helpers:subagent-engineeringfor agent design - Output styles — invoke
ai-helpers:output-style-engineeringfor style design - All artifacts — invoke
ai-helpers:prompt-engineeringfor instruction design
This skill provides the SDK reference (what exists, how it works); those skills provide engineering guidance (how to design it well).
{
"sources": {
"Subagents": "https://code.claude.com/docs/en/sub-agents.md",
"Plugins": "https://code.claude.com/docs/en/plugins.md",
"Plugins Reference": "https://code.claude.com/docs/en/plugins-reference.md",
"Discover Plugins": "https://code.claude.com/docs/en/discover-plugins.md",
"Plugin Marketplaces": "https://code.claude.com/docs/en/plugin-marketplaces.md",
"Skills": "https://code.claude.com/docs/en/skills.md",
"Output Styles": "https://code.claude.com/docs/en/output-styles.md",
"Hooks": "https://code.claude.com/docs/en/hooks.md",
"Hooks Guide": "https://code.claude.com/docs/en/hooks-guide.md",
"MCP": "https://code.claude.com/docs/en/mcp.md",
"Settings": "https://code.claude.com/docs/en/settings.md",
"Model Config": "https://code.claude.com/docs/en/model-config.md",
"Memory": "https://code.claude.com/docs/en/memory.md",
"Best Practices": "https://code.claude.com/docs/en/best-practices.md",
"Status Line": "https://code.claude.com/docs/en/statusline.md"
},
"lastFetched": "2026-02-20T08:52:47.807Z"
}
Best Practices Reference
Patterns for getting the most out of Claude Code.
Core Constraint
Claude's context window fills up fast, and performance degrades as it fills.
Context holds your entire conversation, files Claude reads, and command outputs. When full, Claude may "forget" earlier instructions or make more mistakes. Track usage with a custom status line. Context is the most important resource to manage.
Give Claude Verification
This is the single highest-leverage thing you can do.
Claude performs dramatically better when it can verify its own work.
| Strategy | Before | After |
|---|---|---|
| Provide verification | "implement email validation" | "write validateEmail. test: user@example.com=true, invalid=false. run tests after" |
| Verify UI visually | "make dashboard look better" | "[paste screenshot] implement this. take screenshot, compare, list differences and fix" |
| Address root causes | "the build is failing" | "build fails with [error]. fix it, verify build succeeds. address root cause" |
Verification can be tests, a linter, or any Bash command that checks output. UI changes can be verified using the Claude in Chrome extension (opens tabs, tests UI, iterates).
Explore → Plan → Code
Separate research from implementation. Use Plan Mode to prevent solving the wrong problem.
1. Explore (Plan Mode): Claude reads files, answers questions without making changes 2. Plan: Ask Claude to create a detailed implementation plan. Press Ctrl+G to open the plan in your editor for direct editing before Claude proceeds 3. Implement (Normal Mode): Let Claude code, verifying against the plan 4. Commit: Ask Claude to commit with a descriptive message and open a PR
Skip planning for small, clear tasks (describable in one sentence). Use it when uncertain about approach, changing multiple files, or unfamiliar with the code being modified.
Provide Specific Context
| Strategy | Before | After |
|---|---|---|
| Scope the task | "add tests for foo.py" | "test foo.py covering logged-out edge case. avoid mocks" |
| Point to sources | "why weird API?" | "look through git history, summarize how API came to be" |
| Reference patterns | "add calendar widget" | "look at HotDogWidget.php, follow pattern for calendar widget" |
| Describe symptoms | "fix the login bug" | "login fails after timeout. check src/auth/, especially refresh" |
Vague prompts are useful when exploring — "what would you improve in this file?" can surface things you wouldn't have thought to ask about.
Rich Content
- Reference files with
@instead of describing locations — Claude reads before responding - Paste images directly (copy/paste or drag-drop)
- Give URLs for documentation; use
/permissionsto allowlist frequently-used domains - Pipe data:
cat error.log | claude - Let Claude fetch what it needs using Bash commands or MCP tools
Configure Your Environment
Write Effective CLAUDE.md
Run /init to generate a starter file, then refine. CLAUDE.md is loaded every session.
Include:
- Bash commands Claude can't guess
- Code style rules that differ from defaults
- Testing instructions and preferred runners
- Repository etiquette (branch naming, PR conventions)
- Architectural decisions specific to your project
- Common gotchas and non-obvious behaviors
Exclude:
- Anything Claude can figure out by reading code
- Standard conventions Claude already knows
- Detailed API docs (link instead)
- Information that changes frequently
- File-by-file codebase descriptions
Keep it concise. For each line, ask: "Would removing this cause Claude to make mistakes?" If not, cut it. Bloated CLAUDE.md causes Claude to ignore your actual instructions.
Use emphasis (IMPORTANT, YOU MUST) for rules that must not be missed. Check CLAUDE.md into git so your team can contribute.
Import syntax — CLAUDE.md can import other files:
See @README.md for project overview and @package.json for available npm commands.
# Additional Instructions
- Git workflow: @docs/git-instructions.md
- Personal overrides: @~/.claude/my-project-instructions.mdLocations:
~/.claude/CLAUDE.md— applies to all sessions./CLAUDE.md— project root; check into git or nameCLAUDE.local.mdand gitignore it- Parent directories — useful for monorepos (both
root/CLAUDE.mdandroot/foo/CLAUDE.md
are pulled in automatically)
- Child directories — pulled in on demand when working with files in those directories
Configure Permissions
/permissions— allowlist safe commands (e.g.,npm run lint,git commit)/sandbox— OS-level isolation; restricts filesystem and network access--dangerously-skip-permissions— bypass all checks for contained workflows
Warning: Only use --dangerously-skip-permissions in a sandbox without internet access.Risk of data loss, system corruption, or data exfiltration via prompt injection.
Use CLI Tools
Tell Claude to use gh, aws, gcloud, sentry-cli for external services. CLI tools are the most context-efficient integration method. Claude can also learn unfamiliar CLIs:
Use 'foo-cli-tool --help' to learn about foo tool, then use it to solve A, B, C.Connect MCP Servers
claude mcp add connects external tools: Notion, Figma, databases, issue trackers.
Set Up Hooks
Hooks run scripts at specific workflow points. Unlike CLAUDE.md instructions (advisory), hooks are deterministic — guaranteed to run.
Write a hook that runs eslint after every file edit
Write a hook that blocks writes to the migrations folderRun /hooks for interactive configuration, or edit .claude/settings.json directly.
Create Skills
.claude/skills/<name>/SKILL.md for domain knowledge and reusable workflows. Skills load on demand without bloating every conversation.
Create Subagents
.claude/agents/<name>.md for specialized assistants running in isolated context with their own allowed tools. Useful for tasks that read many files or need specialized focus.
Install Plugins
/plugin to browse the marketplace. Plugins bundle skills, hooks, subagents, and MCP servers into a single installable unit.
Communicate Effectively
Ask Codebase Questions
Ask Claude questions you'd ask another engineer:
- How does logging work?
- How do I make a new API endpoint?
- What does this code do on line 134?
- Why does this call
foo()instead ofbar()?
Let Claude Interview You
For larger features, have Claude gather requirements before coding:
I want to build [brief description]. Interview me using the AskUserQuestion tool.
Ask about technical implementation, UI/UX, edge cases, concerns, and tradeoffs.
Don't ask obvious questions — dig into the hard parts I might not have considered.
Keep interviewing until covered, then write a complete spec to SPEC.md.Then start a fresh session to execute the spec. Clean context focused entirely on implementation.
Manage Your Session
Course-Correct Early
Esc— stop mid-action; context is preserved, redirect immediatelyEsc + Escor/rewind— open rewind menu to restore previous state"Undo that"— have Claude revert its changes/clear— reset between unrelated tasks
After two failed corrections, /clear and write a better initial prompt incorporating what you learned. A clean session with a better prompt almost always outperforms a long session with accumulated corrections.
Manage Context Aggressively
/clearfrequently between tasks to reset entirely- Auto-compaction triggers near context limits; Claude summarizes what matters most
/compact <instructions>for manual control (e.g.,/compact Focus on the API changes)- Partial rewind:
Esc + Escor/rewind, select a checkpoint, choose **Summarize from
here** — condenses from that point while keeping earlier context intact
- Customize compaction in CLAUDE.md: `"When compacting, always preserve the full list of
modified files and any test commands"`
Use Subagents for Investigation
Use subagents to investigate how authentication handles token refresh,
and whether we have any existing OAuth utilities I should reuse.Subagents explore in a separate context window, keeping your main conversation clean. Also useful for post-implementation verification:
use a subagent to review this code for edge casesRewind with Checkpoints
Every Claude action creates a checkpoint. Esc + Esc or /rewind opens the menu.
Options:
- Restore conversation only (keep code changes)
- Restore code only (keep conversation)
- Restore both
- Summarize from selected message
Checkpoints persist across sessions — close your terminal, still rewind later.
Note: Checkpoints only track changes made by Claude, not external processes.
Not a replacement for git.
Resume Conversations
claude --continue # Resume most recent conversation
claude --resume # Select from recent conversationsUse /rename to give sessions descriptive names ("oauth-migration", "memory-leak-debug"). Treat sessions like branches — different workstreams can have separate persistent contexts.
Automate and Scale
Headless Mode
claude -p "Explain what this project does"
claude -p "List all API endpoints" --output-format json
claude -p "Analyze this log file" --output-format stream-jsonUse in CI pipelines, pre-commit hooks, or any automated workflow. --verbose for debugging, off in production. Pipe output: claude -p "<prompt>" --output-format json | your_command
Parallel Sessions
Multiple sessions for quality-focused workflows — fresh context improves review since Claude won't be biased toward code it just wrote.
| Session A (Writer) | Session B (Reviewer) |
|---|---|
Implement a rate limiter for our API endpoints | |
| `Review @src/middleware/rateLimiter.ts. Look for edge cases, | |
| race conditions, consistency with existing middleware.` | |
Here's review feedback: [output]. Address these issues |
Or: one Claude writes tests, another writes code to pass them.
Options: Desktop app (visual, isolated worktrees), Claude Code on the web (cloud VMs), Agent teams (automated coordination with shared tasks and messaging).
Fan Out Across Files
for file in $(cat files.txt); do
claude -p "Migrate $file from React to Vue. Return OK or FAIL." \
--allowedTools "Edit,Bash(git commit *)"
doneTest on 2-3 files first, refine the prompt, then run at scale. --allowedTools restricts what Claude can do in unattended runs.
Safe Autonomous Mode
--dangerously-skip-permissions lets Claude work uninterrupted (no permission checks). Works well for lint fixing, boilerplate generation. Use only in a container without internet access.
With /sandbox enabled, you get similar autonomy with better security — defined upfront boundaries rather than bypassing all checks.
Common Failure Patterns
| Pattern | Fix |
|---|---|
| Kitchen sink session | /clear between unrelated tasks |
| Correcting over and over | After 2 fails, /clear and write better initial prompt |
| Over-specified CLAUDE.md | Ruthlessly prune; convert satisfied rules to hooks |
| Trust-then-verify gap | Always provide verification (tests, scripts, screenshots) |
| Infinite exploration | Scope narrowly or use subagents to protect main context |
Develop Intuition
Patterns are starting points. Pay attention to what works:
- When Claude produces great output, notice the prompt structure and context you provided
- When Claude struggles, ask why — context too noisy? prompt too vague? task too big?
Over time, you'll know when to be specific vs open-ended, when to plan vs explore, when to clear context vs let it accumulate.
Hooks Reference
Hooks are shell commands or LLM prompts that execute automatically at specific points in Claude Code's lifecycle. They provide deterministic control — certain actions always happen rather than relying on the LLM to choose to run them.
Hook Lifecycle
| Event | When It Fires |
|---|---|
SessionStart | Session begins or resumes |
UserPromptSubmit | User submits prompt, before processing |
PreToolUse | Before tool call executes (can block) |
PermissionRequest | Permission dialog appears |
PostToolUse | After tool call succeeds |
PostToolUseFailure | After tool call fails |
Notification | Claude Code sends a notification |
SubagentStart | Subagent spawned |
SubagentStop | Subagent finishes |
Stop | Claude finishes responding |
TeammateIdle | Agent team teammate about to go idle |
TaskCompleted | Task being marked as completed |
ConfigChange | Configuration file changes during session |
PreCompact | Before context compaction |
SessionEnd | Session terminates |
All matching hooks run in parallel. Identical hook commands are deduplicated automatically.
Configuration
Hook Locations
| Location | Scope | Shareable |
|---|---|---|
~/.claude/settings.json | All your projects | No, local to machine |
.claude/settings.json | Single project | Yes, commit to repo |
.claude/settings.local.json | Single project | No, gitignored |
| Managed policy settings | Organization-wide | Admin-controlled |
Plugin hooks/hooks.json | When plugin enabled | Yes, bundled |
| Skill/agent YAML frontmatter | While component is active | Yes |
Basic Structure
Three levels of nesting: event → matcher group → hook handler(s).
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs prettier --write"
}
]
}
]
}
}Matcher Patterns
The matcher field is a regex string. Use "*", "", or omit it entirely to match all occurrences. Each event type matches on a different field:
| Event | Matches On | Example Values |
|---|---|---|
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest | Tool name | Bash, `Edit\ |
SessionStart | How session started | startup, resume, clear, compact |
SessionEnd | Why session ended | clear, logout, prompt_input_exit, bypass_permissions_disabled, other |
Notification | Notification type | permission_prompt, idle_prompt, auth_success, elicitation_dialog |
SubagentStart, SubagentStop | Agent type | Bash, Explore, Plan, custom agent names |
PreCompact | Trigger type | manual, auto |
ConfigChange | Config source | user_settings, project_settings, local_settings, policy_settings, skills |
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted | No matcher support | Always fires on every occurrence |
Matchers are case-sensitive. Edit|Write matches either tool; Notebook.* matches any tool starting with "Notebook".
MCP Tool Matching
MCP tools follow the pattern mcp__<server>__<tool>:
mcp__memory__create_entitiesmcp__filesystem__read_file
Match patterns: mcp__memory__.* (all from memory server), mcp__.*__write.* (any write tool across servers).
Hook Handler Fields
Common Fields
| Field | Required | Default | Description |
|---|---|---|---|
type | Yes | — | "command", "prompt", or "agent" |
timeout | No | 600/30/60 | Seconds before cancel (command/prompt/agent defaults) |
statusMessage | No | — | Custom spinner message while hook runs |
once | No | false | Run only once per session then removed (skills only) |
Command Hook Fields
| Field | Required | Description |
|---|---|---|
command | Yes | Shell command to execute |
async | No | If true, runs in background without blocking |
Prompt/Agent Hook Fields
| Field | Required | Description |
|---|---|---|
prompt | Yes | Prompt text; use $ARGUMENTS as placeholder for hook input JSON |
model | No | Model to use; defaults to a fast model |
Reference Scripts by Path
Hook commands execute from Claude Code's current working directory, which changes when Claude performs cd operations. Relative paths break silently — the hook disappears with no error. Always use absolute paths via environment variables:
{ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh" }For plugins:
{ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh" }Plugin Hooks
Define plugin hooks in hooks/hooks.json. Supports an optional top-level description field. Plugin hooks merge with user and project hooks when the plugin is enabled.
{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh", "timeout": 30 }
]
}
]
}
}Hooks in Skills and Agents
Define hooks directly in skill or agent YAML frontmatter. Scoped to the component's lifetime; cleaned up when it finishes. All events supported. For subagents, Stop hooks are automatically converted to SubagentStop.
---
name: secure-operations
description: Perform operations with security checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/security-check.sh"
---The /hooks Menu
Type /hooks in Claude Code to view, add, and delete hooks interactively. Labels indicate source: [User], [Project], [Local], [Plugin] (read-only).
To disable all hooks: use the toggle in /hooks or set "disableAllHooks": true in settings. Individual hooks cannot be disabled without removing them.
Important: Claude Code captures hooks at startup. External file edits don't take effect mid-session without review in /hooks. Hooks added through /hooks take effect immediately.
disableAllHooks in user/project settings cannot disable managed policy hooks. Only disableAllHooks at the managed settings level can disable those.
---
Hook Input and Output
Common Input Fields
All hooks receive JSON on stdin:
| Field | Description |
|---|---|
session_id | Current session identifier |
transcript_path | Path to conversation JSON |
cwd | Current working directory |
permission_mode | "default", "plan", "acceptEdits", "dontAsk", or "bypassPermissions" |
hook_event_name | Name of the event that fired |
Exit Code Behavior
| Exit Code | Meaning |
|---|---|
| 0 | Success; Claude Code parses stdout for JSON output |
| 2 | Blocking error; stderr fed to Claude or shown to user |
| Other | Non-blocking error; stderr shown in verbose mode (Ctrl+O) |
For UserPromptSubmit and SessionStart, stdout on exit 0 is added as Claude context. JSON output is only processed on exit 0. Choosing exit 2 ignores any JSON in stdout.
Exit Code 2 Behavior Per Event
| Event | Can Block? | What Happens on Exit 2 |
|---|---|---|
PreToolUse | Yes | Blocks the tool call |
PermissionRequest | Yes | Denies the permission |
UserPromptSubmit | Yes | Blocks prompt and erases it from context |
Stop | Yes | Prevents Claude from stopping; continues the conversation |
SubagentStop | Yes | Prevents the subagent from stopping |
TeammateIdle | Yes | Prevents teammate from going idle; teammate continues working |
TaskCompleted | Yes | Prevents task from being marked completed |
ConfigChange | Yes | Blocks config change from taking effect (except policy_settings) |
PostToolUse | No | Shows stderr to Claude (tool already ran) |
PostToolUseFailure | No | Shows stderr to Claude (tool already failed) |
Notification | No | Shows stderr to user only |
SubagentStart | No | Shows stderr to user only |
SessionStart | No | Shows stderr to user only |
SessionEnd | No | Shows stderr to user only |
PreCompact | No | Shows stderr to user only |
JSON Output Fields
On exit 0, stdout can contain a JSON object with these universal fields:
| Field | Default | Description |
|---|---|---|
continue | true | If false, Claude stops entirely. Takes precedence over event-specific decisions |
stopReason | none | Shown to user when continue is false. Not shown to Claude |
suppressOutput | false | If true, hides stdout from verbose mode |
systemMessage | none | Warning message shown to the user |
To stop Claude entirely regardless of event:
{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }Decision Control Patterns
Different events use different patterns for blocking or controlling behavior:
| Events | Pattern | Key Fields |
|---|---|---|
UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop, ConfigChange | Top-level decision | decision: "block", reason |
TeammateIdle, TaskCompleted | Exit code only | Exit 2 blocks; stderr fed as feedback |
PreToolUse | hookSpecificOutput | permissionDecision (allow/deny/ask), permissionDecisionReason |
PermissionRequest | hookSpecificOutput | decision.behavior (allow/deny) |
---
Hook Events
SessionStart
Runs when session starts or resumes. Keep these hooks fast — they run on every session. Use for dynamic context injection; for static context, use CLAUDE.md instead.
Matcher values: startup, resume, clear, compact
Additional input fields:
| Field | Description |
|---|---|
source | How the session started: "startup", "resume", "clear", "compact" |
model | Model identifier |
agent_type | Agent name (only when started with claude --agent <name>) |
Input example:
{
"source": "startup",
"model": "claude-sonnet-4-6"
}Output:
- Plain stdout is added as Claude's context
additionalContextfield inhookSpecificOutputis added more discretely
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Context to inject"
}
}Persist environment variables:
$CLAUDE_ENV_FILE is available only in SessionStart hooks. Write export statements to this path to make environment variables available in all subsequent Bash commands. Use append (>>) to preserve variables set by other hooks:
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fiTo capture environment changes from setup commands:
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---
UserPromptSubmit
Runs when user submits a prompt, before Claude processes it. Use to add context, validate prompts, or block certain input types.
No matcher support — fires on every prompt.
Additional input fields:
| Field | Description |
|---|---|
prompt | Text the user submitted |
Output:
| Field | Description |
|---|---|
decision | "block" prevents processing and erases the prompt from context |
reason | Shown to user when decision is "block". Not added to context |
additionalContext | String added to Claude's context (more discrete than plain stdout) |
Plain text stdout is also added as context (shown as hook output in transcript).
{
"decision": "block",
"reason": "Explanation",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Additional context for Claude"
}
}---
PreToolUse
Runs after Claude creates tool parameters, before executing the tool call.
Matcher: Tool name — Bash, Edit, Write, Read, Glob, Grep, Task, WebFetch, WebSearch, or any MCP tool name.
Additional input fields:
| Field | Description |
|---|---|
tool_name | Name of the tool being called |
tool_input | Tool-specific input parameters |
tool_use_id | Unique identifier for this tool call |
Tool input schemas:
| Tool | Key Fields |
|---|---|
| Bash | command, description, timeout, run_in_background |
| Write | file_path, content |
| Edit | file_path, old_string, new_string, replace_all |
| Read | file_path, offset, limit |
| Glob | pattern, path |
| Grep | pattern, path, glob, output_mode, -i, multiline |
| WebFetch | url, prompt |
| WebSearch | query, allowed_domains, blocked_domains |
| Task | prompt, description, subagent_type, model |
Output (uses hookSpecificOutput — not top-level decision):
| Field | Description |
|---|---|
permissionDecision | "allow" bypasses permissions, "deny" cancels the call, "ask" prompts the user |
permissionDecisionReason | For allow/ask: shown to user. For deny: shown to Claude |
updatedInput | Modifies tool input before execution. Combine with allow or ask |
additionalContext | String added to Claude's context before tool executes |
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed",
"updatedInput": { "field": "new value" },
"additionalContext": "Production environment — proceed with caution"
}
}Deprecated: The previous top-leveldecision/reasonfields are deprecated for
PreToolUse. Old values"approve"and"block"map to"allow"and"deny".
Other events (PostToolUse,Stop) still use top-leveldecision.
---
PermissionRequest
Runs when a permission dialog is about to be shown to the user. Does not fire in non-interactive mode (-p); use PreToolUse instead for automated permission decisions.
Matcher: Tool name (same values as PreToolUse).
Additional input fields: Same as PreToolUse (without tool_use_id), plus:
| Field | Description |
|---|---|
permission_suggestions | Array of "always allow" options the user would normally see |
Output:
| Field | Description |
|---|---|
behavior | "allow" grants permission, "deny" denies it |
updatedInput | For allow: modifies tool input before execution |
updatedPermissions | For allow: applies permission rules (equivalent to user selecting "always allow") |
message | For deny: tells Claude why permission was denied |
interrupt | For deny: if true, stops Claude |
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": { "command": "npm run lint" },
"updatedPermissions": []
}
}
}---
PostToolUse
Runs immediately after a tool completes successfully. Cannot undo the action — use PreToolUse to block before execution.
Matcher: Tool name (same values as PreToolUse).
Additional input fields: tool_name, tool_input, tool_response, tool_use_id.
Output:
| Field | Description |
|---|---|
decision | "block" prompts Claude with the reason. Omit to allow processing to continue |
reason | Shown to Claude when decision is "block" |
additionalContext | Additional context for Claude |
updatedMCPToolOutput | MCP tools only: replaces the tool's output with this value |
{
"decision": "block",
"reason": "Lint errors detected",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "See lint output above"
}
}---
PostToolUseFailure
Runs when a tool execution fails (throws error or returns failure result). Use for logging, alerts, or providing corrective context to Claude.
Matcher: Tool name (same values as PreToolUse).
Additional input fields:
| Field | Description |
|---|---|
tool_name | Name of the failed tool |
tool_input | Arguments sent to the tool |
tool_use_id | Unique identifier for this tool call |
error | String describing what went wrong |
is_interrupt | Optional boolean — whether failure was caused by user interruption |
Output: additionalContext in hookSpecificOutput.
{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Check network connectivity for this failure"
}
}---
Notification
Runs when Claude Code sends a notification. Cannot block notifications.
Matcher values: permission_prompt, idle_prompt, auth_success, elicitation_dialog
Additional input fields:
| Field | Description |
|---|---|
message | Notification text |
title | Optional title |
notification_type | Which type fired (same as matcher) |
Output: additionalContext in hookSpecificOutput (adds to conversation context).
---
SubagentStart
Runs when a subagent is spawned via the Task tool. Cannot block subagent creation.
Matcher: Agent type — Bash, Explore, Plan, or custom agent names.
Additional input fields:
| Field | Description |
|---|---|
agent_id | Unique identifier for this subagent |
agent_type | Agent type name (used for matching) |
Output: additionalContext in hookSpecificOutput (injected into subagent's context).
---
SubagentStop
Runs when a subagent finishes responding.
Matcher: Agent type (same values as SubagentStart).
Additional input fields:
| Field | Description |
|---|---|
stop_hook_active | Whether already continuing from a stop hook |
agent_id | Unique subagent identifier |
agent_type | Agent type name (used for matching) |
agent_transcript_path | Path to subagent's own transcript (in subagents/ folder) |
last_assistant_message | Text content of subagent's final response |
Note: transcript_path is the main session's transcript; agent_transcript_path is the subagent's.
Output: Same as Stop — decision: "block" prevents stopping.
---
Stop
Runs when the main Claude Code agent finishes responding. Does not fire on user interrupts.
No matcher support — fires on every stop.
Additional input fields:
| Field | Description |
|---|---|
stop_hook_active | true when already continuing from a stop hook |
last_assistant_message | Text content of Claude's final response |
Output:
{
"decision": "block",
"reason": "Must continue because tests are still failing"
}Critical: Always check stop_hook_active to prevent infinite loops:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Allow Claude to stop
fi
# ... rest of hook logic---
TeammateIdle
Runs when an agent team teammate is about to go idle after finishing its turn. Use to enforce quality gates before a teammate stops.
No matcher support — fires on every occurrence.
Additional input fields:
| Field | Description |
|---|---|
teammate_name | Name of the teammate about to go idle |
team_name | Name of the team |
Output: Exit code only — no JSON decision control.
- Exit 2: blocks idle; stderr is fed to the teammate as feedback (it continues working)
- Exit 0: allows the teammate to go idle
#!/bin/bash
if [ ! -f "./dist/output.js" ]; then
echo "Build artifact missing. Run the build before stopping." >&2
exit 2
fi
exit 0---
TaskCompleted
Runs when a task is being marked as completed. Fires when any agent calls TaskUpdate to complete a task, or when a teammate finishes its turn with in-progress tasks.
No matcher support — fires on every occurrence.
Additional input fields:
| Field | Description |
|---|---|
task_id | Identifier of the task being completed |
task_subject | Title of the task |
task_description | Detailed description (may be absent) |
teammate_name | Teammate completing the task (may be absent) |
team_name | Name of the team (may be absent) |
Output: Exit code only — no JSON decision control.
- Exit 2: blocks completion; stderr fed as feedback to the model
#!/bin/bash
INPUT=$(cat)
if ! npm test 2>&1; then
echo "Tests must pass before completing: $(echo "$INPUT" | jq -r '.task_subject')" >&2
exit 2
fi
exit 0---
ConfigChange
Runs when a configuration file changes during a session. Use for audit logging or blocking unauthorized modifications.
Matcher values: user_settings, project_settings, local_settings, policy_settings, skills
Additional input fields:
| Field | Description |
|---|---|
source | Which configuration type changed |
file_path | Path to the changed file (optional) |
Output:
{
"decision": "block",
"reason": "Configuration changes require admin approval"
}policy_settings changes cannot be blocked — hooks still fire (useful for audit logging) but blocking decisions are ignored. This ensures enterprise-managed settings always apply.
---
PreCompact
Runs before a compaction operation.
Matcher values: manual, auto
Additional input fields:
| Field | Description |
|---|---|
trigger | "manual" (from /compact) or "auto" (context window full) |
custom_instructions | User's instructions from /compact; empty for auto |
No decision control. Cannot block compaction.
---
SessionEnd
Runs when a session ends. Cannot block session termination.
Matcher values: clear, logout, prompt_input_exit, bypass_permissions_disabled, other
Additional input fields:
| Field | Description |
|---|---|
reason | Why the session ended |
No decision control. Use for cleanup, logging session statistics, or saving state.
---
Hook Types
Prompt-Based Hooks (type: "prompt")
Sends hook input and your prompt to a Claude model (Haiku by default) for a yes/no decision. Supported events: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, UserPromptSubmit, Stop, SubagentStop, TaskCompleted. Not supported for TeammateIdle.
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "prompt",
"prompt": "Check if all tasks are complete. $ARGUMENTS",
"timeout": 30
}]
}]
}
}Use $ARGUMENTS as placeholder for the hook input JSON. If absent, input is appended.
Response schema:
{ "ok": true }or
{ "ok": false, "reason": "Explanation fed back to Claude" }When ok is false, the reason is fed back to Claude as its next instruction.
Agent-Based Hooks (type: "agent")
Like prompt hooks but spawns a subagent that can use Read, Grep, Glob tools to verify conditions. Up to 50 turns before returning a decision. Same event support and response schema as prompt hooks. Default timeout: 60 seconds.
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "agent",
"prompt": "Verify all unit tests pass. Run the test suite and check results. $ARGUMENTS",
"timeout": 120
}]
}]
}
}Use prompt hooks when hook input data alone is sufficient. Use agent hooks when you need to inspect actual files or run commands to verify conditions.
Async Hooks (async: true)
Runs in the background without blocking Claude. Only available for type: "command".
{
"type": "command",
"command": "/path/to/run-tests.sh",
"async": true,
"timeout": 120
}- Cannot block tool calls or return decisions — the triggering action has already proceeded
- Output (
systemMessageoradditionalContext) is delivered on the next conversation turn - Each firing creates a separate background process — no deduplication across firings
- Prompt-based hooks cannot run asynchronously
---
Security
Hooks run with your full user permissions. They can modify, delete, or access any file your user account can access.
Best practices:
- Validate and sanitize inputs — never trust input data blindly
- Quote shell variables:
"$VAR"not$VAR - Block path traversal: check for
..in file paths - Use absolute paths for scripts, using
"$CLAUDE_PROJECT_DIR"for the project root - Skip sensitive files: avoid
.env,.git/, keys, credentials
---
Debugging and Troubleshooting
Debug Output
Run claude --debug to see hook execution details (matched hooks, exit codes, stdout). Toggle verbose mode with Ctrl+O to see hook output in the transcript.
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Executing hook command: <command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <stdout>Hook Not Firing
- Run
/hooksand confirm the hook appears under the correct event - Check matcher pattern matches exactly (matchers are case-sensitive)
- Confirm the correct event type (
PreToolUsefires before,PostToolUsefires after) PermissionRequesthooks do not fire in non-interactive mode (-p) — usePreToolUse
Testing a Hook Manually
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $? # Check exit codeInfinite Stop Hook Loop
Check stop_hook_active and exit early if true:
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fiJSON Validation Failed
Shell profile printing text before JSON. Claude Code spawns a shell that sources ~/.zshrc or ~/.bashrc. Unconditional echo statements corrupt the output. Wrap them in an interactive check:
# In ~/.zshrc or ~/.bashrc
if [[ $- == *i* ]]; then
echo "Shell ready"
fiSettings Edits Not Taking Effect
Direct edits to settings files don't apply mid-session. Claude Code snapshots hooks at startup to prevent malicious modifications. Open /hooks to review and apply changes.
MCP Reference
Model Context Protocol (MCP) connects Claude Code to external tools and services.
Installing MCP Servers
HTTP Server (Recommended)
claude mcp add --transport http <name> <url>
# Example
claude mcp add --transport http notion https://mcp.notion.com/mcp
# With authentication header
claude mcp add --transport http secure-api https://api.example.com/mcp \
--header "Authorization: Bearer your-token"SSE Server (Deprecated)
claude mcp add --transport sse <name> <url>Prefer HTTP where available.
Stdio Server (Local)
claude mcp add [options] <name> -- <command> [args...]
# Example
claude mcp add --transport stdio --env AIRTABLE_API_KEY=YOUR_KEY airtable \
-- npx -y airtable-mcp-serverImportant: All options (--transport, --env, --scope, --header) must come before the server name. -- separates server name from the command and its arguments.
Windows: Use cmd /c wrapper for npx:
claude mcp add --transport stdio my-server -- cmd /c npx -y @some/packageWithout it, Windows cannot execute npx directly ("Connection closed" errors).
Managing Servers
# List all
claude mcp list
# Get details
claude mcp get github
# Remove
claude mcp remove github
# Check server status (within Claude Code)
/mcpDynamic Tool Updates
Claude Code supports MCP list_changed notifications. When a server sends this notification, Claude Code automatically refreshes available tools, prompts, and resources — no reconnection needed.
Installation Scopes
| Scope | Storage | Use Case |
|---|---|---|
| local | ~/.claude.json (project path) | Personal, current project (default) |
| project | .mcp.json in project root | Team, via version control |
| user | ~/.claude.json | Personal, all projects |
claude mcp add --transport http stripe --scope user https://mcp.stripe.comPrecedence: local > project > user (higher scope overrides lower).
Project-Scope Configuration
.mcp.json in project root (checked into version control):
{
"mcpServers": {
"shared-server": {
"command": "/path/to/server",
"args": [],
"env": {}
}
}
}Claude Code prompts for approval before using project-scoped servers. Reset approval choices:
claude mcp reset-project-choicesEnvironment Variable Expansion
Supported in .mcp.json for command, args, env, url, and headers:
{
"mcpServers": {
"api-server": {
"type": "http",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}Syntax:
${VAR}— expands to value${VAR:-default}— expands to value or default
Fails to parse if a required variable is unset and has no default.
Authentication
OAuth 2.0 (Dynamic Client Registration)
For servers that support automatic OAuth setup:
# Add server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
# Authenticate in Claude Code
/mcp
# Follow browser login flowTokens stored securely and refreshed automatically. Use "Clear authentication" in /mcp to revoke access.
Pre-Configured OAuth Credentials
For servers that don't support dynamic client registration (error: "Incompatible auth server: does not support dynamic client registration"), register an OAuth app through the server's developer portal first.
| Flag | Purpose |
|---|---|
--client-id | OAuth client ID from developer portal |
--client-secret | Prompts for secret with masked input |
--callback-port | Port for redirect URI (http://localhost:PORT/callback) |
Via `claude mcp add`:
claude mcp add --transport http \
--client-id your-client-id --client-secret --callback-port 8080 \
my-server https://mcp.example.com/mcpVia `claude mcp add-json`:
claude mcp add-json my-server \
'{"type":"http","url":"https://mcp.example.com/mcp","oauth":{"clientId":"your-client-id","callbackPort":8080}}' \
--client-secretVia environment variable (CI):
MCP_CLIENT_SECRET=your-secret claude mcp add --transport http \
--client-id your-client-id --client-secret --callback-port 8080 \
my-server https://mcp.example.com/mcpNotes:
- Client secret stored in system keychain (macOS) or credentials file, not in config
- For public OAuth clients with no secret, use
--client-idalone without--client-secret - OAuth flags only apply to HTTP and SSE transports; no effect on stdio
- Verify with
claude mcp get <name>
Add from JSON
claude mcp add-json <name> '<json>'
# HTTP server
claude mcp add-json weather-api \
'{"type":"http","url":"https://api.weather.com/mcp","headers":{"Authorization":"Bearer token"}}'
# Stdio server
claude mcp add-json local-weather \
'{"type":"stdio","command":"/path/to/weather-cli","args":["--api-key","abc123"],"env":{"CACHE_DIR":"/tmp"}}'
# HTTP server with OAuth
claude mcp add-json my-server \
'{"type":"http","url":"https://mcp.example.com/mcp","oauth":{"clientId":"your-client-id","callbackPort":8080}}' \
--client-secretSupports --scope user for user-wide configuration.
Import from Claude Desktop
claude mcp add-from-claude-desktop- macOS and WSL only
- Interactive dialog to select which servers to import
- Supports
--scope user - Duplicate names get numerical suffix (e.g.,
server_1)
Use MCP Servers from Claude.ai
When logged into Claude Code with a Claude.ai account, MCP servers configured in Claude.ai are automatically available:
- Configure servers at
claude.ai/settings/connectors - On Team/Enterprise plans, only admins can add servers
- Complete authentication steps in Claude.ai first
- Servers appear in
/mcpwith Claude.ai indicators - No additional setup needed in Claude Code
Use Claude Code as MCP Server
claude mcp serveClaude Desktop configuration (claude_desktop_config.json):
{
"mcpServers": {
"claude-code": {
"type": "stdio",
"command": "claude",
"args": ["mcp", "serve"],
"env": {}
}
}
}If claude is not in PATH, use the full path (which claude). Exposes Claude Code tools (View, Edit, LS, etc.) to the MCP client. The client is responsible for user confirmation on tool calls.
Plugin-Provided MCP Servers
Plugins can bundle MCP servers. Define in .mcp.json at plugin root:
{
"database-tools": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_URL": "${DB_URL}"
}
}
}Or inline in plugin.json:
{
"name": "my-plugin",
"mcpServers": {
"plugin-api": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/api-server",
"args": ["--port", "8080"]
}
}
}| Feature | Details |
|---|---|
| Automatic lifecycle | Starts on plugin enable; requires Claude Code restart on changes |
| Environment variables | ${CLAUDE_PLUGIN_ROOT} resolves to plugin directory |
| User env access | Same variables as manually configured servers |
| Transport types | Supports stdio, SSE, and HTTP |
Plugin servers appear in /mcp with indicators showing plugin origin. Managed through plugin installation, not /mcp commands.
MCP Resources
Reference resources with @ in prompts:
> Can you analyze @github:issue://123?
> Compare @postgres:schema://users with @docs:file://database/user-modelFormat: @server:protocol://resource/path. Resources are fetched and included as attachments. Fuzzy-searchable in @ autocomplete.
MCP Prompts as Commands
MCP servers can expose prompts that become slash commands:
/mcp__github__list_prs
/mcp__github__pr_review 456
/mcp__jira__create_issue "Bug in login flow" high- Discovered dynamically from connected servers
- Arguments parsed from prompt's defined parameters
- Results injected directly into conversation
- Server and prompt names normalized (spaces become underscores)
MCP Tool Search
When MCP tool descriptions exceed 10% of the context window, Tool Search activates automatically. Tools load on-demand instead of being preloaded. Requires Sonnet 4+ or Opus 4+ (Haiku not supported).
Configure via `ENABLE_TOOL_SEARCH`:
| Value | Behavior |
|---|---|
auto | Activate at 10% threshold (default) |
auto:<N> | Custom threshold (e.g., auto:5 = 5%) |
true | Always enabled |
false | Disabled, all tools loaded upfront |
ENABLE_TOOL_SEARCH=auto:5 claudeSet in settings.json env field, or disable via disallowedTools:
{
"permissions": {
"deny": ["MCPSearch"]
}
}For MCP server authors: Use the server instructions field to describe what category of tasks your tools handle and when Claude should search for them. This is the primary signal Tool Search uses to discover your server's tools.
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
MCP_TIMEOUT | Server startup timeout in ms | (system) |
MAX_MCP_OUTPUT_TOKENS | Maximum tokens for MCP tool output | 25000 |
ENABLE_TOOL_SEARCH | Tool search behavior (see above) | auto |
MCP_CLIENT_SECRET | OAuth client secret for non-interactive setup | — |
Output warning threshold is 10,000 tokens; increase limit:
export MAX_MCP_OUTPUT_TOKENS=50000
claude---
Managed MCP Configuration
Two options for organizational control over MCP servers:
Option 1: Exclusive Control (managed-mcp.json)
Deploy for complete control. Users cannot add, modify, or use any other servers.
| Platform | Path |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/managed-mcp.json |
| Linux / WSL | /etc/claude-code/managed-mcp.json |
| Windows | C:\Program Files\ClaudeCode\managed-mcp.json |
System-wide paths requiring administrator privileges.
{
"mcpServers": {
"github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/" },
"company-internal": {
"type": "stdio",
"command": "/usr/local/bin/company-mcp-server",
"args": ["--config", "/etc/company/mcp-config.json"],
"env": { "COMPANY_API_URL": "https://internal.company.com" }
}
}
}Option 2: Policy-Based Control (Allowlists / Denylists)
Use allowedMcpServers and deniedMcpServers in managed settings. Users can add their own servers within policy constraints.
Restriction types (each entry must have exactly one):
| Type | Matches | Example |
|---|---|---|
serverName | Configured server name | {"serverName": "github"} |
serverCommand | Exact command array (stdio only) | {"serverCommand": ["npx", "-y", "pkg"]} |
serverUrl | URL pattern with * wildcards | {"serverUrl": "https://mcp.company.com/*"} |
{
"allowedMcpServers": [
{"serverName": "github"},
{"serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]},
{"serverUrl": "https://mcp.company.com/*"}
],
"deniedMcpServers": [
{"serverName": "dangerous-server"},
{"serverUrl": "https://*.untrusted.com/*"}
]
}URL wildcard patterns:
https://mcp.company.com/*— all paths on domainhttps://*.example.com/*— any subdomainhttp://localhost:*/*— any port on localhost
Allowlist behavior:
| Value | Effect |
|---|---|
undefined | No restrictions (default) |
[] | Complete lockdown, no servers allowed |
| List | Only matching servers allowed |
Denylist behavior:
| Value | Effect |
|---|---|
undefined | No servers blocked (default) |
[] | No servers blocked |
| List | Matching servers explicitly blocked |
Precedence rules:
- Denylist takes absolute precedence over allowlist
- A server passes if it matches any name, command, or URL entry (unless denied)
- When
serverCommandentries exist in allowlist, stdio servers must match a command —
cannot pass by name alone
- When
serverUrlentries exist in allowlist, remote servers must match a URL pattern —
cannot pass by name alone
- Options 1 and 2 can combine:
managed-mcp.jsonhas exclusive user control, but
allowlists/denylists still filter which managed servers actually load
---
Troubleshooting
Server Not Starting
1. Check command exists and is executable 2. Verify paths use ${CLAUDE_PLUGIN_ROOT} for plugin servers 3. Run claude --debug to inspect logs 4. Test server process manually 5. Adjust startup timeout: MCP_TIMEOUT=10000 claude
Authentication Failures
- For OAuth errors: run
/mcpand use "Clear authentication", then re-authenticate - For "does not support dynamic client registration": use pre-configured OAuth credentials
with --client-id and --client-secret
Tools Not Appearing
- Verify server is configured:
claude mcp get <name> - Check server implements MCP protocol correctly
- Look for connection timeouts in
claude --debugoutput - Check
/mcpfor server status
Large Output Issues
If MCP tools produce excessive output, set MAX_MCP_OUTPUT_TOKENS or configure the server to paginate or filter responses.
Memory Management Reference
Claude Code persists instructions across sessions using two mechanisms:
- CLAUDE.md files: Markdown files you write with instructions, rules, and preferences
- Auto memory: Notes Claude writes for itself based on what it discovers during sessions
Both load into context at session start. More specific instructions take precedence over broader ones.
Memory Hierarchy
| Memory Type | Location | Purpose | Shared With |
|---|---|---|---|
| Managed policy | System paths (see below) | Organization-wide instructions | All users in organization |
| Project memory | ./CLAUDE.md or ./.claude/CLAUDE.md | Team-shared project instructions | Team via source control |
| Project rules | ./.claude/rules/*.md | Modular topic-specific instructions | Team via source control |
| User memory | ~/.claude/CLAUDE.md | Personal preferences for all projects | Just you (all projects) |
| Project memory (local) | ./CLAUDE.local.md | Personal project-specific preferences | Just you (current project) |
| Auto memory | ~/.claude/projects/<project>/memory/ | Claude's automatic notes and learnings | Just you (per project) |
Managed policy paths:
- macOS:
/Library/Application Support/ClaudeCode/CLAUDE.md - Linux:
/etc/claude-code/CLAUDE.md - Windows:
C:\Program Files\ClaudeCode\CLAUDE.md
Loading behavior:
- CLAUDE.md files in parent directories (up to cwd) are loaded in full at launch
- CLAUDE.md files in child directories load on demand when Claude reads files in those subtrees
CLAUDE.local.mdis automatically added to.gitignore
Auto Memory
Claude automatically saves learnings, patterns, and insights as it works. Unlike CLAUDE.md (instructions you write for Claude), auto memory contains notes Claude writes for itself.
Storage: ~/.claude/projects/<project>/memory/ — derived from git repository root, so all subdirectories share one memory directory. Git worktrees get separate directories. Outside a git repo, the working directory is used instead.
Structure:
~/.claude/projects/<project>/memory/
├── MEMORY.md # Index file, first 200 lines loaded into every session
├── debugging.md # Topic files loaded on demand
├── patterns.md
└── ...Behavior:
- First 200 lines of
MEMORY.mdinjected into system prompt at session start - Content beyond 200 lines not loaded automatically — move detailed notes to topic files
- Topic files read on demand via standard file tools (not loaded at startup)
- Claude reads and writes memory files during sessions
Control:
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 # Force off
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=0 # Force on (opt in during rollout)Manage via /memory command or tell Claude directly: "remember that we use pnpm".
Import Syntax
CLAUDE.md files can import additional files using @path/to/import:
See @README for project overview and @package.json for available npm commands.
# Additional Instructions
- git workflow @docs/git-instructions.md
- Personal overrides @~/.claude/my-project-instructions.mdRules:
- Both relative and absolute paths allowed; relative paths resolve relative to the importing file
- Home directory paths (
~/.claude/...) work — useful for sharing instructions across worktrees - Imports not evaluated inside code spans/blocks
- Recursive imports supported (max 5 hops)
- First encounter of external imports triggers one-time approval dialog per project; once
declined, imports remain disabled for that project
- Run
/memoryto see all loaded memory files
Memory Lookup
Claude Code reads memories recursively:
1. Starting in cwd, recurses up to (but not including) root / 2. Reads any CLAUDE.md or CLAUDE.local.md found along the way 3. Discovers nested CLAUDE.md in subtrees when reading files in those directories
Load from Additional Directories
The --add-dir flag gives access to additional directories. To also load memory files from those directories:
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../shared-configCommands
| Command | Action |
|---|---|
/memory | Open any memory file in system editor; see loaded files |
/init | Bootstrap a CLAUDE.md for the current project |
Modular Rules with .claude/rules/
Organize instructions into multiple focused files:
your-project/
├── .claude/
│ ├── CLAUDE.md # Main project instructions
│ └── rules/
│ ├── code-style.md
│ ├── testing.md
│ └── security.mdAll .md files in .claude/rules/ loaded as project memory (same priority as .claude/CLAUDE.md). Files are discovered recursively; subdirectories are supported.
Path-Specific Rules
Scope rules to specific files using YAML frontmatter:
---
paths:
- "src/api/**/*.ts"
---
# API Development Rules
- All API endpoints must include input validation
- Use the standard error response formatRules without paths field apply to all files.
Glob Patterns
| Pattern | Matches |
|---|---|
**/*.ts | All TypeScript files in any directory |
src/**/* | All files under src/ |
*.md | Markdown files in project root |
src/components/*.tsx | React components in specific directory |
Multiple patterns and brace expansion:
---
paths:
- "src/**/*.{ts,tsx}"
- "{src,lib}/**/*.ts"
- "tests/**/*.test.ts"
---Symlinks
Share common rules across projects:
ln -s ~/shared-claude-rules .claude/rules/shared
ln -s ~/company-standards/security.md .claude/rules/security.mdCircular symlinks handled gracefully.
User-Level Rules
Personal rules in ~/.claude/rules/ apply to all projects. Loaded before project rules (project rules have higher priority).
Organization-Level Management
Deploy centrally managed CLAUDE.md via configuration management (MDM, Group Policy, Ansible) to the managed policy location.
Best Practices
- Be specific: "Use 2-space indentation" not "Format code properly"
- Use structure: Bullet points grouped under descriptive headings
- Review periodically: Update as project evolves
- Keep rules focused: Each file should cover one topic
- Use descriptive filenames: Filename should indicate content
- Use conditional rules sparingly: Only add
pathswhen rules truly apply to specific
file types
- Organize with subdirectories: Group related rules (e.g.,
frontend/,backend/)
Model Configuration Reference
Configure which Claude model runs in Claude Code, control effort levels, manage extended context, and pin versions for third-party providers.
Model Aliases
| Alias | Resolves To | Notes |
|---|---|---|
default | Depends on account tier | Always available, even with availableModels |
sonnet | Latest Sonnet (4.6) | Daily coding tasks |
opus | Latest Opus (4.6) | Complex reasoning tasks |
haiku | Latest Haiku | Fast, simple tasks |
sonnet[1m] | Sonnet with 1M context | Long sessions, large codebases |
opusplan | Opus + Sonnet hybrid | Opus in plan mode, Sonnet in execution |
Aliases always track the latest version. Pin with full model name (e.g., claude-opus-4-6) or override env vars.
---
Setting the Model
Methods listed by precedence (highest first):
| Method | Syntax | Scope |
|---|---|---|
/model command | `/model <alias\ | name>` |
--model flag | `claude --model <alias\ | name>` |
ANTHROPIC_MODEL | Environment variable | Shell environment |
Settings model | "model": "opus" in settings | Persistent |
---
Default Model by Account Type
| Account Type | Default Model |
|---|---|
| Max, Team Premium | Opus 4.6 |
| Pro, Team Standard | Sonnet 4.6 |
| Pay-as-you-go (API) | Sonnet 4.5 |
| Enterprise | Opus 4.6 available, not default |
Claude Code may auto-fallback from Opus to Sonnet at usage thresholds.
---
Enterprise Model Restrictions
Set availableModels in managed or policy settings to restrict selectable models. Applies to /model, --model, and ANTHROPIC_MODEL.
{
"model": "sonnet",
"availableModels": ["sonnet", "haiku"]
}defaultis never restricted — always available regardless ofavailableModels- Empty array
[]still allowsdefaultfor the user's tier - Arrays merge and deduplicate across settings scopes
- Managed/policy settings take highest priority for strict enforcement
---
opusplan Mode
Automated hybrid that switches models based on plan mode state:
| Mode | Model Used | Purpose |
|---|---|---|
| Plan mode | opus | Complex reasoning, architecture |
| Execution | sonnet | Code generation, implementation |
Set via any model-setting method: /model opusplan, --model opusplan, ANTHROPIC_MODEL=opusplan, or "model": "opusplan" in settings.
---
Effort Levels
Control Opus 4.6 adaptive reasoning depth. Only supported on Opus.
| Level | Behavior |
|---|---|
low | Faster, cheaper — straightforward tasks |
medium | Balanced reasoning |
high | Deepest reasoning — complex problems (default) |
Setting effort:
| Method | How |
|---|---|
/model picker | Left/right arrow keys for effort slider |
| Environment variable | `CLAUDE_CODE_EFFORT_LEVEL=low\ |
| Settings | `"effortLevel": "low\ |
---
Extended Context (1M Tokens)
Beta: Features, pricing, and availability may change.
Supported on Opus 4.6 and Sonnet 4.6. Append [1m] to any alias or full model name: sonnet[1m], claude-sonnet-4-6[1m].
Billing: Standard rates up to 200K tokens. Beyond 200K, long-context pricing applies. Subscribers pay via extra usage, not subscription.
Availability:
| Account Type | Access |
|---|---|
| API / pay-as-you-go | Full access |
| Pro, Max, Teams, Enterprise | Requires extra usage enabled |
---
Model Override Environment Variables
Override which concrete model each alias resolves to. Values must be full model names (or provider-specific equivalents).
| Variable | Controls |
|---|---|
ANTHROPIC_DEFAULT_OPUS_MODEL | opus alias; opusplan in plan mode |
ANTHROPIC_DEFAULT_SONNET_MODEL | sonnet alias; opusplan in execution mode |
ANTHROPIC_DEFAULT_HAIKU_MODEL | haiku alias; background functionality |
CLAUDE_CODE_SUBAGENT_MODEL | Model used by subagents |
ANTHROPIC_SMALL_FAST_MODEL is deprecated — use ANTHROPIC_DEFAULT_HAIKU_MODEL.
---
Third-Party Provider Model Pinning
When using Bedrock, Vertex AI, or Foundry, pin all three alias overrides to provider-specific version IDs. Without pinning, new Anthropic model releases can silently break users who lack access to the latest version.
| Provider | Example value for ANTHROPIC_DEFAULT_OPUS_MODEL |
|---|---|
| Bedrock | us.anthropic.claude-opus-4-6-v1 |
| Vertex AI | claude-opus-4-6 |
| Foundry | claude-opus-4-6 |
Apply the same pattern to ANTHROPIC_DEFAULT_SONNET_MODEL and ANTHROPIC_DEFAULT_HAIKU_MODEL.
availableModels filtering matches on alias name (opus, sonnet, haiku), not the provider-specific model ID.
---
Prompt Caching Environment Variables
Claude Code uses prompt caching by default. Disable globally or per-model tier.
| Variable | Effect |
|---|---|
DISABLE_PROMPT_CACHING | 1 to disable all caching (overrides others) |
DISABLE_PROMPT_CACHING_HAIKU | 1 to disable for Haiku only |
DISABLE_PROMPT_CACHING_SONNET | 1 to disable for Sonnet only |
DISABLE_PROMPT_CACHING_OPUS | 1 to disable for Opus only |
Global DISABLE_PROMPT_CACHING takes precedence over per-model variables.
---
Checking Current Model
| Method | How |
|---|---|
| Status line | If configured (see statusline reference) |
/status | Shows model and account information |
Output Styles Reference
Action Required: When creating, editing, or improving output styles,
invoke the ai-helpers:output-style-engineering skill first.Output styles adapt Claude Code for uses beyond software engineering by modifying the system prompt. They replace parts of the default prompt rather than appending to it.
Built-in Styles
| Style | Description |
|---|---|
| Default | Efficient software engineering |
| Explanatory | Educational "Insights" between tasks, explains implementation choices/patterns |
| Learning | Collaborative mode; shares Insights + adds TODO(human) markers for you to implement |
How Output Styles Work
- All styles exclude efficient-output instructions (e.g., "respond concisely")
- Custom styles exclude coding instructions unless
keep-coding-instructions: true - Style instructions are appended to the end of the system prompt
- Reminders are triggered during conversation to maintain style adherence
Change Your Output Style
/output-style # interactive menu (also accessible from /config)
/output-style explanatory # direct switchChanges apply at local project level and are saved to .claude/settings.local.json. You can also directly edit the outputStyle field in any settings file at any scope.
Create Custom Output Styles
Custom styles are Markdown files with frontmatter, stored at:
| Scope | Path |
|---|---|
| User | ~/.claude/output-styles/ |
| Project | .claude/output-styles/ |
---
name: My Custom Style
description: Brief description shown in /output-style UI
keep-coding-instructions: true
---
# Custom Style Instructions
You are an interactive CLI tool that helps users with software engineering
tasks. [Your custom instructions here...]
## Specific Behaviors
[Define how the assistant should behave...]Frontmatter
| Field | Purpose | Default |
|---|---|---|
name | Display name | From filename |
description | Shown in /output-style UI | None |
keep-coding-instructions | Keep coding-related parts of the default system prompt | false |
Comparisons
| Feature | Modifies system prompt | Subtractive | Additive | Scope |
|---|---|---|---|---|
| Output styles | Yes | Yes | Yes | Always active |
| CLAUDE.md | No (added as user msg) | No | Yes | Always loaded |
--append-system-prompt | Yes (append only) | No | Yes | Session flag |
| Agents | No (own system prompt) | — | — | Task-invoked |
| Skills | No (injected prompt) | — | Yes | On-demand |
Key distinctions:
- vs CLAUDE.md: Output styles replace parts of the default prompt; CLAUDE.md adds content
as a user message after the system prompt — it cannot remove default instructions.
- vs `--append-system-prompt`: That flag only appends; output styles can also suppress
default sections.
- vs Agents: Agents are invoked for specific tasks and control model, tools, and context.
Output styles only affect the main agent's system prompt.
- vs Skills: Output styles are always active once selected and shape formatting/tone.
Skills are task-specific and invoked on demand.
Plugins Reference
Action Required: When working on plugin components, invoke specialized skills:
- Skills → ai-helpers:skill-engineering- Agents/subagents → ai-helpers:subagent-engineering- Output styles → ai-helpers:output-style-engineeringPlugins package and distribute Claude Code extensions: skills, agents, hooks, MCP servers, LSP servers, output styles, and default settings.
When to Use Plugins vs Standalone
| Approach | Skill Names | Best For |
|---|---|---|
Standalone (.claude/) | /hello | Personal workflows, project-specific, experiments |
| Plugins | /plugin-name:hello | Sharing with team, distributing, versioned releases |
Plugin Structure
my-plugin/
├── .claude-plugin/ # Metadata directory (optional)
│ └── plugin.json # Plugin manifest
├── commands/ # Simple markdown commands (legacy; prefer skills/)
│ └── status.md
├── skills/ # Skills with SKILL.md
│ └── code-reviewer/
│ └── SKILL.md
├── agents/ # Custom subagents
│ └── security-reviewer.md
├── hooks/ # Hook configurations
│ └── hooks.json
├── output-styles/ # Output style definitions
│ └── concise.md
├── settings.json # Default settings (only `agent` key supported)
├── .mcp.json # MCP server definitions
├── .lsp.json # LSP server configurations
└── scripts/ # Utility scripts
└── format-code.shCritical: Don't put commands/, agents/, skills/, or hooks/ inside .claude-plugin/. Only plugin.json goes there.
Plugin Manifest (plugin.json)
Located at .claude-plugin/plugin.json. The manifest is optional — Claude Code auto-discovers components in default locations and derives the plugin name from the directory name. Use a manifest when you need metadata or custom component paths.
Required Fields
| Field | Type | Description |
|---|---|---|
name | string | Unique identifier (kebab-case, no spaces) |
The name is used as the namespace for skills: a skill hello in plugin my-plugin invokes as /my-plugin:hello. Also used in install commands: plugin-name@marketplace-name.
Metadata Fields
| Field | Type | Description | Example |
|---|---|---|---|
version | string | Semantic version | "2.1.0" |
description | string | Brief explanation | "Deployment tools" |
author | object | Author info | {"name": "Dev", "email": ""} |
homepage | string | Documentation URL | "https://docs.example.com" |
repository | string | Source code URL | "https://github.com/..." |
license | string | License identifier | "MIT", "Apache-2.0" |
keywords | array | Discovery tags | ["deployment", "ci-cd"] |
Component Path Fields
| Field | Type | Description |
|---|---|---|
commands | string\ | array |
agents | string\ | array |
skills | string\ | array |
hooks | string\ | object |
mcpServers | string\ | object |
outputStyles | string\ | array |
lspServers | string\ | object |
All paths are relative to plugin root and must start with ./. Custom paths supplement default directories — they don't replace them.
Complete Example
{
"name": "my-plugin",
"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"],
"commands": ["./custom/commands/special.md"],
"agents": "./custom/agents/",
"skills": "./custom/skills/",
"hooks": "./config/hooks.json",
"mcpServers": "./mcp-config.json",
"outputStyles": "./styles/",
"lspServers": "./.lsp.json"
}Environment Variable
${CLAUDE_PLUGIN_ROOT} — absolute path to the plugin directory. Use this in hooks, MCP servers, and scripts to ensure correct paths regardless of installation location.
{
"hooks": {
"PostToolUse": [{
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/process.sh"
}]
}]
}
}Default Settings (settings.json)
Plugins can ship a settings.json at the plugin root. Currently only the agent key is supported. Setting agent activates one of the plugin's custom agents as the main thread agent, applying its system prompt, tool restrictions, and model.
{
"agent": "security-reviewer"
}settings.json takes priority over settings declared in plugin.json. Unknown keys are silently ignored.
Skill Arguments ($ARGUMENTS)
Skills support dynamic input via the $ARGUMENTS placeholder. Any text after the skill name is injected into $ARGUMENTS in SKILL.md.
---
description: Greet the user with a personalized message
---
Greet the user named "$ARGUMENTS" warmly.Invocation: /my-plugin:hello Alex → $ARGUMENTS = "Alex".
Installation Scopes
| Scope | Settings File | Use Case |
|---|---|---|
user | ~/.claude/settings.json | Personal, all projects (default) |
project | .claude/settings.json | Team, via version control |
local | .claude/settings.local.json | Project-specific, gitignored |
managed | managed-settings.json | Admin-controlled (read-only) |
Plugin Discovery UI (/plugin)
The /plugin command opens a tabbed interface:
| Tab | Purpose |
|---|---|
| Discover | Browse available plugins from all marketplaces |
| Installed | View/manage installed plugins, grouped by scope |
| Marketplaces | Add, remove, update marketplace sources |
| Errors | View plugin loading errors (e.g. missing LSP binary) |
Navigate tabs with Tab / Shift+Tab. Type to filter by name/description.
CLI Commands
# Install
claude plugin install <plugin>@<marketplace> [--scope user|project|local]
# Manage
claude plugin uninstall <plugin> # aliases: remove, rm
claude plugin enable <plugin>
claude plugin disable <plugin>
claude plugin update <plugin> # supports --scope managed
# Validate plugin or marketplace
claude plugin validate .Test Locally
# Load plugin during development (not cached)
claude --plugin-dir ./my-plugin
# Multiple plugins
claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two---
Plugin Components
Skills
skills/
├── pdf-processor/
│ ├── SKILL.md
│ ├── reference.md # optional
│ └── scripts/ # optional
└── code-reviewer/
└── SKILL.mdEach SKILL.md needs frontmatter with at minimum description. Skills appear in /help under the plugin namespace and Claude invokes them based on task context.
Agents
Markdown files in agents/ directory:
---
description: What this agent specializes in and when Claude should invoke it
---
Detailed system prompt for the agent describing its role, expertise, and behavior.Agents appear in /agents and Claude can invoke them automatically based on context.
Output Styles
Markdown files in output-styles/ directory at plugin root, or specified via outputStyles in plugin.json.
Hooks
In hooks/hooks.json (or inline in plugin.json under hooks):
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh"
}]
}]
}
}Available hook events (15):
| Event | When It Fires |
|---|---|
PreToolUse | Before Claude uses any tool |
PostToolUse | After Claude successfully uses a tool |
PostToolUseFailure | After tool execution fails |
PermissionRequest | When a permission dialog is shown |
UserPromptSubmit | When user submits a prompt |
Notification | When Claude Code sends notifications |
Stop | When Claude attempts to stop |
SubagentStart | When a subagent is started |
SubagentStop | When a subagent attempts to stop |
SessionStart | At the beginning of sessions |
SessionEnd | At the end of sessions |
TeammateIdle | When a team teammate is about to go idle |
TaskCompleted | When a task is marked completed |
ConfigChange | When a configuration file changes |
PreCompact | Before conversation history is compacted |
Hook types: command (shell), prompt (LLM evaluation with $ARGUMENTS), agent (agentic verifier with tools).
MCP Servers
In .mcp.json (or inline in plugin.json under mcpServers):
{
"mcpServers": {
"plugin-database": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_PATH": "${CLAUDE_PLUGIN_ROOT}/data"
}
}
}
}Plugin MCP servers start automatically when the plugin is enabled and appear as standard MCP tools in Claude's toolkit.
LSP Servers
In .lsp.json (or inline in plugin.json under lspServers):
{
"go": {
"command": "gopls",
"args": ["serve"],
"extensionToLanguage": {
".go": "go"
}
}
}Users must install the language server binary separately. LSP plugins configure the connection, not the server itself.
Required fields: command, extensionToLanguage.
Optional fields:
| Field | Description |
|---|---|
args | Command-line arguments |
transport | stdio (default) or socket |
env | Environment variables |
initializationOptions | Options passed during initialization |
settings | Passed via workspace/didChangeConfiguration |
workspaceFolder | Workspace folder path |
startupTimeout | Max startup wait (ms) |
shutdownTimeout | Max shutdown wait (ms) |
restartOnCrash | Auto-restart on crash |
maxRestarts | Max restart attempts |
Pre-built LSP plugins (official marketplace, install language server binary first):
| Plugin | Language | Binary Required |
|---|---|---|
clangd-lsp | C/C++ | clangd |
csharp-lsp | C# | csharp-ls |
gopls-lsp | Go | gopls |
jdtls-lsp | Java | jdtls |
kotlin-lsp | Kotlin | kotlin-language-server |
lua-lsp | Lua | lua-language-server |
php-lsp | PHP | intelephense |
pyright-lsp | Python | pyright-langserver |
rust-analyzer-lsp | Rust | rust-analyzer |
swift-lsp | Swift | sourcekit-lsp |
typescript-lsp | TypeScript | typescript-language-server |
Create custom LSP plugins only for languages not covered above.
Plugin Caching
Claude Code copies marketplace plugins to ~/.claude/plugins/cache. Implications:
- Paths referencing files outside plugin directory won't work after installation
- Use symlinks for external dependencies (symlinks are followed during copy)
--plugin-dirplugins are used in-place and are not cached
---
Marketplaces
Marketplaces are catalogs for distributing plugins. Using a marketplace is two steps: 1. Add the marketplace (registers the catalog, installs nothing) 2. Install individual plugins from it
The official Anthropic marketplace (claude-plugins-official) is available automatically. All others must be added manually.
Marketplace File
Create .claude-plugin/marketplace.json at the repository root:
{
"name": "company-tools",
"owner": {
"name": "DevTools Team",
"email": "devtools@example.com"
},
"metadata": {
"description": "Internal development tools",
"pluginRoot": "./plugins"
},
"plugins": [
{
"name": "code-formatter",
"source": "./plugins/formatter",
"description": "Automatic code formatting",
"version": "2.1.0"
},
{
"name": "deployment-tools",
"source": {
"source": "github",
"repo": "company/deploy-plugin"
},
"description": "Deployment automation tools"
}
]
}Marketplace Schema
Required fields:
| Field | Type | Description |
|---|---|---|
name | string | Marketplace identifier (kebab-case). Used in install commands. |
owner | object | Maintainer info: name (required), email (optional) |
plugins | array | List of available plugins |
Reserved names (cannot be used): claude-code-marketplace, claude-code-plugins, claude-plugins-official, anthropic-marketplace, anthropic-plugins, agent-skills, life-sciences.
Optional metadata:
| Field | Type | Description |
|---|---|---|
metadata.description | string | Brief marketplace description |
metadata.version | string | Marketplace version |
metadata.pluginRoot | string | Base dir prepended to relative source paths (e.g. "./plugins") |
Plugin Entry Fields
Each entry requires name and source, plus any fields from the plugin manifest schema:
| Field | Type | Description |
|---|---|---|
name | string | Plugin identifier (required) |
source | string\ | object |
version | string | Plugin version (see version resolution below) |
strict | boolean | Authority control (default: true) |
category | string | Category for organization |
tags | array | Tags for searchability |
commands | string\ | array |
agents | string\ | array |
hooks | string\ | object |
mcpServers | string\ | object |
lspServers | string\ | object |
Strict Mode
Controls whether plugin.json or the marketplace entry is the authority for component definitions.
| Value | Behavior |
|---|---|
true (default) | plugin.json is authority; marketplace entry can supplement |
false | Marketplace entry is the entire definition; plugin.json components conflict |
Use strict: false when the marketplace operator wants full control over which components are exposed (e.g. curating a plugin's components differently than the plugin author intended).
Version Resolution
Version can be set in plugin.json or in the marketplace entry. plugin.json always wins silently when both are set.
- Relative-path plugins: set version in marketplace entry
- All other sources: set version in
plugin.json
Avoid setting version in both places — the marketplace version will be silently ignored.
Plugin Sources
| Source | Type | Fields |
|---|---|---|
| Relative path | string (e.g. "./my-plugin") | — |
github | object | repo (required), ref?, sha? |
url | object | url (must end .git), ref?, sha? |
npm | object | package, version?, registry? |
pip | object | package, version?, registry? |
Relative paths only work with Git-based marketplaces (not URL-based). For URL-based distribution, use github, url, or npm sources.
Source Examples
// GitHub
{"source": {"source": "github", "repo": "owner/repo", "ref": "v2.0.0", "sha": "a1b2c3..."}}
// Git URL
{"source": {"source": "url", "url": "https://gitlab.com/team/plugin.git", "ref": "main"}}
// npm
{"source": {"source": "npm", "package": "@company/my-plugin", "version": "1.0.0"}}
// pip
{"source": {"source": "pip", "package": "my-plugin", "version": "1.0.0"}}Add Marketplaces
# GitHub (owner/repo format)
/plugin marketplace add owner/repo
# Git URL (HTTPS or SSH, optional #ref for branch/tag)
/plugin marketplace add https://gitlab.com/company/plugins.git
/plugin marketplace add https://gitlab.com/company/plugins.git#v1.0.0
# Local path or direct marketplace.json
/plugin marketplace add ./my-marketplace
/plugin marketplace add ./path/to/marketplace.json
# Remote URL (direct marketplace.json — relative plugin paths won't work)
/plugin marketplace add https://example.com/marketplace.jsonShortcut: /plugin market instead of /plugin marketplace.
Manage Marketplaces
/plugin marketplace list
/plugin marketplace update marketplace-name
/plugin marketplace remove marketplace-name # aliases: rm — also uninstalls pluginsAuto-Update Control
Official marketplaces: auto-update enabled by default. Third-party/local: disabled by default. Toggle per-marketplace via /plugin → Marketplaces → select → Enable/Disable auto-update.
| Environment Variable | Effect |
|---|---|
DISABLE_AUTOUPDATER | Disables all auto-updates (Claude Code + plugins) |
FORCE_AUTOUPDATE_PLUGINS=true | Keeps plugin auto-updates even when DISABLE_AUTOUPDATER is set |
# Manual Claude Code updates, automatic plugin updates
export DISABLE_AUTOUPDATER=true
export FORCE_AUTOUPDATE_PLUGINS=trueTeam Configuration
In .claude/settings.json — prompts team members to install when they trust the project:
{
"extraKnownMarketplaces": {
"company-tools": {
"source": {
"source": "github",
"repo": "your-org/claude-plugins"
}
}
},
"enabledPlugins": {
"formatter@company-tools": true,
"deployment-tools@company-tools": true
}
}Managed Marketplace Restrictions (strictKnownMarketplaces)
Administrators restrict which marketplaces users can add via managed settings. Cannot be overridden by user or project settings. Validated before any network requests.
| Value | Behavior |
|---|---|
| Undefined (default) | No restrictions — users can add any marketplace |
Empty array [] | Complete lockdown — no new marketplaces allowed |
| List of sources | Allowlist — only matching marketplaces allowed |
Supported allowlist source types:
| Source Type | Required Fields | Matching |
|---|---|---|
github | repo; opt ref, path | Exact match on all specified fields |
url | url | Full URL exact match |
hostPattern | hostPattern | Regex matched against marketplace host |
{
"strictKnownMarketplaces": [
{"source": "github", "repo": "acme-corp/approved-plugins"},
{"source": "hostPattern", "hostPattern": "^github\\.example\\.com$"}
]
}Release Channels
To run stable/latest channels, create two marketplace files pointing to different ref or sha values. Each pinned ref must declare a different version in plugin.json — if two refs have the same version, Claude Code treats them as identical and skips the update.
Private Repositories
Manual install/update uses existing git credential helpers (gh auth, macOS Keychain, etc.). For background auto-updates, set authentication tokens in your environment:
| Provider | Environment Variable |
|---|---|
| GitHub | GITHUB_TOKEN or GH_TOKEN |
| GitLab | GITLAB_TOKEN or GL_TOKEN |
| Bitbucket | BITBUCKET_TOKEN |
Validation
# Validate plugin structure and marketplace JSON
claude plugin validate .
# From within Claude Code
/plugin validate .---
Debugging
Run claude --debug (or /debug in TUI) to see plugin loading details: which plugins load, manifest errors, command/agent/hook registration, MCP server initialization.
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Plugin not loading | Invalid plugin.json | Validate with claude plugin validate |
| Commands not appearing | Wrong directory layout | Ensure commands/ at root |
| Hooks not firing | Script not executable | chmod +x script.sh |
| MCP server fails | Missing plugin root var | Use ${CLAUDE_PLUGIN_ROOT} |
| LSP executable not found | Binary not installed | Install the language server binary |
| Plugin skills not showing | Stale cache | rm -rf ~/.claude/plugins/cache, reinstall |
Hook Troubleshooting
- Script must be executable:
chmod +x ./scripts/your-script.sh - Shebang line required:
#!/bin/bashor#!/usr/bin/env bash - Event names are case-sensitive:
PostToolUsenotpostToolUse - Matcher pattern must match tool name:
"matcher": "Write|Edit"
Common Error Messages
| Error | Cause / Fix |
|---|---|
Invalid JSON syntax: Unexpected token } at position 142 | Missing/extra comma or unquoted string in JSON |
name: Required | Missing required field in manifest |
No commands found in plugin ... custom directory | Path exists but contains no .md or SKILL.md files |
Plugin directory not found at path: ./plugins/my-plugin | Wrong source path in marketplace entry |
conflicting manifests: both plugin.json and marketplace | Remove component declarations from one source |
Version Management
Use semantic versioning: MAJOR.MINOR.PATCH
- MAJOR: Breaking changes
- MINOR: New features (backward-compatible)
- PATCH: Bug fixes
{
"name": "my-plugin",
"version": "2.1.0"
}Document changes in CHANGELOG.md. Always bump version before distributing — if version doesn't change, existing users won't receive updates due to caching.