--- name: claude-code description: Use when configuring Claude Code — installing skills or agents, writing hook configurations, setting up tool permissions, registering MCP servers, or authoring CLAUDE.md project instructions. --- # Claude Code Setup Configuration and customization reference for Claude Code — skills, commands, agents, hooks, permissions, and MCP servers. ## When to Activate - Setting up skills, slash commands, or agents in a new project or globally - Writing or debugging hook configurations in `settings.json` - Configuring tool permissions to reduce approval prompts - Registering or troubleshooting an MCP server - Writing `CLAUDE.md` project instructions - Asking how Claude Code loads context or resolves settings - Integrating Claude Code with VS Code or JetBrains ## Directory Layout ``` ~/.claude/ # global — applies to all projects ├── settings.json # global permissions, hooks, env vars ├── CLAUDE.md # global instructions read at every session ├── skills/ │ └── /skill.md # or .md (flat) ├── agents/ │ └── .md └── commands/ └── .md / ├── CLAUDE.md # project instructions (commit this) └── .claude/ ├── settings.json # project permissions + hooks (commit this) ├── settings.local.json # personal overrides (gitignore this) ├── skills/ # project-scoped skills ├── agents/ # project-scoped agents └── commands/ # project-scoped commands ``` Settings are merged: `settings.local.json` overrides `.claude/settings.json` overrides `~/.claude/settings.json`. ## Skills Skills are markdown files that Claude loads contextually when the task matches. ### File Format ```markdown --- name: my-skill description: One keyword-dense sentence used for activation matching. --- # Title One-sentence intro. ## When to Activate - Verb-leading trigger condition - Another trigger condition ## Content sections… ## Checklist - [ ] At least one item ``` ### Installation ```bash # Single skill (global) cp -r skills/my-skill ~/.claude/skills/ # All skills from a library cp -r skills/* ~/.claude/skills/ # Project-scoped (available only in this project) cp -r skills/my-skill .claude/skills/ ``` ### How Skills Load Claude matches the task description against the `description` frontmatter field and the `## When to Activate` bullet points. No manual invocation needed — skills activate automatically. The `name` field must match the folder name (or file stem for flat layout). ## Slash Commands Slash commands are prompt templates invoked with `/command-name` in the Claude Code prompt. ### File Format ```markdown Do the thing the user asked. ## Instructions 1. First step — use `$ARGUMENTS` for any text the user typed after the command name 2. Second step 3. Output format… ``` `$ARGUMENTS` is replaced with everything the user typed after the command name: ``` /my-command foo bar → $ARGUMENTS = "foo bar" /my-command → $ARGUMENTS = "" ``` ### Examples ```markdown Summarize the file at $ARGUMENTS. Read the file, identify the top 3 key points, and return them as a numbered list. Each point should be one sentence. ``` ```markdown Fix GitHub issue #$ARGUMENTS in this repository. 1. Run `gh issue view $ARGUMENTS` to read the issue 2. Find the relevant code 3. Implement the fix 4. Write or update tests 5. Summarize what changed ``` ### Installation ```bash # Global (available in all projects) cp .claude/commands/my-command.md ~/.claude/commands/ # Project-only (stays in this repo) # Already in .claude/commands/ — no copy needed ``` ## Agents Agents run in an isolated context window with their own tool set and system prompt. ### File Format ```markdown --- name: my-agent description: Use this agent when… (triggers auto-delegation) tools: Read, Grep, Glob, Bash model: sonnet color: blue --- You are a … agent. Your job is to … ## Methodology Step-by-step approach… ## Output Format What the agent should return… ``` ### Frontmatter Fields | Field | Values | Notes | |---|---|---| | `name` | kebab-case string | Must match filename stem | | `description` | One sentence | Controls when Claude auto-delegates — write as "Use this agent when…" | | `tools` | Comma-separated tool names | Omit to inherit all tools; restrict for read-only agents | | `model` | `sonnet`, `opus`, `haiku`, `inherit` | `inherit` uses the parent session's model | | `color` | `red` `blue` `green` `yellow` `purple` `orange` | UI accent only | ### Available Tools ``` Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, Agent, TaskCreate, TaskUpdate, TaskList, NotebookEdit ``` Principle of least privilege: a read-only audit agent should declare `tools: Read, Grep, Glob, Bash` — no `Write` or `Edit`. ### Installation ```bash # Global cp .claude/agents/my-agent.md ~/.claude/agents/ # Project-only # Already in .claude/agents/ — committed with the repo ``` ## Hooks Hooks run shell commands automatically in response to Claude Code events. ### Settings Structure ```json { "hooks": { "EventName": [ { "matcher": "ToolName", "hooks": [ { "type": "command", "command": "shell command here", "timeout": 10, "async": false } ] } ] } } ``` ### Hook Events | Event | When it fires | Matcher targets | |---|---|---| | `SessionStart` | Once at session open | Empty string `""` | | `UserPromptSubmit` | Every time user submits a message | Message content substring | | `PreToolUse` | Before a tool call executes | Tool name | | `PostToolUse` | After a tool call completes | Tool name | | `PreCompact` | Before context window compaction | Empty string `""` | | `Stop` | When Claude finishes a turn | Empty string `""` | ### Hook Environment Variables | Variable | Available in | Value | |---|---|---| | `$CLAUDE_FILE_PATH` | `Write`, `Edit` hooks | Absolute path of the file | | `$CLAUDE_TOOL_NAME` | All tool hooks | Name of the tool being called | | `$CLAUDE_TOOL_INPUT` | All tool hooks | JSON-encoded tool input | | `$CLAUDE_TOOL_OUTPUT` | `PostToolUse` only | JSON-encoded tool output | ### Common Hook Patterns ```json { "hooks": { "PostToolUse": [ { "matcher": "Write", "hooks": [ { "type": "command", "command": "prettier --write $CLAUDE_FILE_PATH", "if": "Write(**/*.ts)" }, { "type": "command", "command": "black $CLAUDE_FILE_PATH", "if": "Write(**/*.py)" } ] }, { "matcher": "Edit", "hooks": [ { "type": "command", "command": "eslint --fix $CLAUDE_FILE_PATH", "if": "Edit(**/*.ts)" }, { "type": "command", "command": "ruff check --fix $CLAUDE_FILE_PATH", "if": "Edit(**/*.py)" } ] }, { "matcher": "Bash", "hooks": [ { "type": "command", "command": "echo \"[$(date)] $CLAUDE_TOOL_INPUT\" >> .claude/command.log", "async": true } ] } ], "SessionStart": [ { "matcher": "", "hooks": [{ "type": "command", "command": "git status" }] } ], "Stop": [ { "matcher": "", "hooks": [ { "type": "command", "command": "python ~/tools/notify.py 'Claude finished'", "async": true } ] } ] } } ``` The `if` field inside a hook entry is a secondary glob filter on top of the `matcher`. Use it to handle multiple file types under one `matcher` block. `async: true` — hook runs in background; Claude doesn't wait for it. Use for logging, notifications. `async: false` (default) — Claude waits for the hook to complete before continuing. Use for formatters, validators. ### PreToolUse Blocking A `PreToolUse` hook with exit code `2` blocks the tool call and surfaces the hook's stdout as an error message to Claude. ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash -c 'echo $CLAUDE_TOOL_INPUT | grep -q \"rm -rf\" && { echo \"rm -rf blocked\"; exit 2; } || exit 0'" } ] } ] } } ``` ## Settings and Permissions ### Settings Files ``` ~/.claude/settings.json # global defaults /.claude/settings.json # project (commit — shared with team) /.claude/settings.local.json # personal overrides (gitignore) ``` ### Permissions ```json { "permissions": { "allow": [ "Bash(npm run *)", "Bash(git *)", "Write(**/*.ts)", "Write(**/*.py)", "Bash(docker compose up *)" ], "deny": [ "Bash(git push --force *)", "Bash(rm -rf *)" ] } } ``` Permission string syntax: ``` "Bash(command prefix *)" — allow bash commands matching the prefix "Write(**/*.ext)" — allow writing files matching the glob "Read(**/*)" — allow reading any file "*" — allow everything (use in dev only) ``` Deny rules take precedence over allow rules. ### Environment Variables ```json { "env": { "NODE_ENV": "development", "PYTHONPATH": "/app/src", "LOG_LEVEL": "debug" } } ``` ### Model Override ```json { "model": "claude-opus-4-7" } ``` ## MCP Servers MCP (Model Context Protocol) servers expose tools and resources to Claude Code. ### Registration ```bash # Register globally (available in all projects) claude mcp add -s user [args...] # Register for current project only (stored in .claude/mcp.json) claude mcp add -s project [args...] # Register locally (personal, stored in .claude/mcp.local.json — gitignored) claude mcp add -s local [args...] ``` ### Examples ```bash # Python MCP server claude mcp add -s user memory_map \ /home/user/memory_map/venv/bin/python \ /home/user/memory_map/server.py # Node MCP server claude mcp add -s user filesystem \ npx @modelcontextprotocol/server-filesystem /tmp # With environment variables claude mcp add -s project my-server \ --env API_KEY=abc123 \ node server.js ``` ### Management ```bash claude mcp list # list all registered servers claude mcp remove # unregister a server claude mcp get # show config for one server ``` MCP config is stored as JSON: ```json { "mcpServers": { "memory_map": { "command": "/home/user/memory_map/venv/bin/python", "args": ["/home/user/memory_map/server.py"] } } } ``` ## CLAUDE.md `CLAUDE.md` files inject persistent instructions into every session. ### Load Order ``` ~/.claude/CLAUDE.md # always loaded (global) /CLAUDE.md # loaded when in that project /src/CLAUDE.md # loaded when working in src/ (scoped) ``` All matching files are concatenated — lower-level files extend rather than replace. ### What to Put in CLAUDE.md ```markdown ## Session Setup 1. Run `load_memory` with the current working directory 2. Run `suggest_history` with the current working directory and the user's first message ## Project Context This is a FastAPI service that handles payment processing. Main entry point: src/main.py. Tests: tests/. ## Conventions - Use `snake_case` for all Python identifiers - Never commit directly to main — always branch - Database migrations live in alembic/versions/ ## Commands - Run tests: `pytest tests/ -x` - Start dev server: `uvicorn src.main:app --reload` - Lint: `ruff check src/` ``` Avoid documenting things derivable from reading the code. Focus on: session setup, non-obvious conventions, workflow automation steps, and external context Claude can't infer. ## IDE Integration ### VS Code Install the **Claude Code** extension from the VS Code marketplace. After installing: ``` Ctrl+Shift+P → "Claude Code: Open" — open Claude Code panel Ctrl+Shift+P → "Claude Code: Focus" — focus without opening a new window ``` The extension reads `.claude/settings.json` from the workspace root automatically. ### JetBrains (IntelliJ, PyCharm, WebStorm, etc.) Install the **Claude Code** plugin from the JetBrains Marketplace. After installing: ``` Tools → Claude Code → Open Session ``` Both IDEs support inline diff review, file context injection, and running Claude Code commands from within the editor. ## Red Flags - **Secrets in CLAUDE.md** — CLAUDE.md is read into every session context and often committed to git; never put API keys, passwords, or tokens there; reference environment variables instead - **Hooks with no `timeout` set** — a hook that hangs (network call, blocked process) suspends Claude Code indefinitely; always set `"timeout": N` seconds on every hook command - **`"deny": ["Bash(*)"]` blocking all shell access** — over-broad deny rules prevent running tests, linters, and build tools; scope deny rules to the specific dangerous patterns (e.g., `rm -rf`, `git push --force`) - **MCP server registered with `--scope project` for personal tools** — project-scoped MCP servers are stored in the repo and apply to everyone who checks it out; use `--scope user` for personal servers - **PostToolUse hook on `Write` that itself uses `Write`** — a write hook that writes files triggers another write event, causing infinite recursion; hooks must not trigger the same event they listen to - **No `matcher` on broad hooks** — a hook with an empty or missing matcher fires on every single tool use; always specify a `matcher` to limit execution to the tool or pattern that needs it - **CLAUDE.md with per-feature implementation notes** — CLAUDE.md is for team-wide project conventions; per-feature context belongs in inline comments, ADRs, or feature-specific docs alongside the code ## Checklist - [ ] Skills installed to `~/.claude/skills/` (global) or `.claude/skills/` (project-scoped) - [ ] Each skill has `name`, `description` frontmatter and a `## When to Activate` section - [ ] Slash commands installed to `~/.claude/commands/` or `.claude/commands/`; use `$ARGUMENTS` for user input - [ ] Agents declare minimum required `tools` — read-only agents exclude `Write` and `Edit` - [ ] Agent `description` written as "Use this agent when…" for correct auto-delegation - [ ] `settings.json` committed to `.claude/` for shared project permissions; personal overrides in `settings.local.json` (gitignored) - [ ] Formatter/linter hooks use `async: false` so files are fixed before Claude continues - [ ] Logging/notification hooks use `async: true` so they don't block Claude - [ ] `PreToolUse` safety hooks exit `2` to block, `0` to allow - [ ] MCP servers registered with correct scope: `user` for personal tools, `project` for shared - [ ] `CLAUDE.md` covers session setup steps, non-obvious conventions, and key commands — not things readable from the code - [ ] Global `~/.claude/CLAUDE.md` contains only instructions that apply across all projects