# Context Engineering for Claude Code Projects

A comprehensive guide to structuring CLAUDE.md files, rules, skills, hooks, and configuration for effective Claude Code projects. Sourced from official Claude Code documentation.

---

## 1. CLAUDE.md Architecture

### Discovery & Loading

Claude Code walks **up** the directory tree from the current working directory, loading every `CLAUDE.md` and `CLAUDE.local.md` it finds:

```
~/.claude/CLAUDE.md                    # User scope (all projects)
/path/to/project/CLAUDE.md            # Project scope (team-shared)
/path/to/project/.claude/CLAUDE.md    # Alternative project location
/path/to/project/CLAUDE.local.md      # Local overrides (gitignored)
packages/foo/CLAUDE.md                 # Subdirectory (lazy-loaded)
```

**Loading order** (all files concatenate — they don't override):

| Priority | Scope | File | When Loaded |
|----------|-------|------|-------------|
| 1 (highest) | Managed | `/Library/Application Support/ClaudeCode/CLAUDE.md` | Session start, cannot exclude |
| 2 | User | `~/.claude/CLAUDE.md` | Session start |
| 3 | Project | `./CLAUDE.md` or `./.claude/CLAUDE.md` | Session start |
| 4 | Local | `./CLAUDE.local.md` | Session start, appended after project |
| 5 | Subdirectory | `subdir/CLAUDE.md` | Lazy — when Claude reads files in that directory |

**Key behavior**: All files are **concatenated in full**, not merged or replaced. When instructions conflict, Claude may pick one arbitrarily. There is no explicit override mechanism.

### What Belongs at Each Level

| Level | Content | Example |
|-------|---------|---------|
| **User** (`~/.claude/CLAUDE.md`) | Personal preferences across all projects | Work style, response format, git workflow preferences |
| **Project** (`./CLAUDE.md`) | Team-shared standards, build commands, architecture | `prek run --all-files`, module structure, coding standards |
| **Local** (`./CLAUDE.local.md`) | Machine-specific settings, gitignored | Sandbox URLs, local test data, personal overrides |
| **Subdirectory** | Package/module-specific rules | `packages/frontend/CLAUDE.md` for React conventions |

### File Imports

CLAUDE.md supports importing other files:

```markdown
See @README.md for project overview.
Git workflow: @docs/git-instructions.md
```

- Paths resolve **relative to the importing file**
- Absolute paths supported: `@~/shared/instructions.md`
- Recursive imports up to **5 levels deep**
- First external import triggers approval dialog

### What Makes Instructions Stick

**Do:**
- Be specific and concrete: `"Use 2-space indentation"` not `"format code properly"`
- Use structured markdown (headers, bullets) — Claude scans structure like a reader
- Include exact commands: `"Run npm test before committing"`
- Keep each file under **200 lines** — longer files reduce adherence

**Don't:**
- Write vague instructions (`"keep code clean"`)
- Contradict instructions across files
- Write dense prose paragraphs
- Put critical instructions only in conversation (lost after compaction)

### CLAUDE.md Survives Compaction

CLAUDE.md is **re-read from disk** after `/compact`. Instructions in CLAUDE.md persist across sessions and compaction. Instructions given only in conversation do not.

### Monorepo Exclusions

Skip irrelevant CLAUDE.md files with `claudeMdExcludes` in `.claude/settings.local.json`:

```json
{
  "claudeMdExcludes": [
    "**/irrelevant-package/CLAUDE.md"
  ]
}
```

---

## 2. Rules System (`.claude/rules/`)

### File Format

Rules are markdown files with optional YAML frontmatter in `.claude/rules/`:

```markdown
---
paths:
  - "src/api/**/*.ts"
  - "src/**/*.{ts,tsx}"
---

# API Development Rules

- All endpoints must include input validation
- Use standard error response format
```

### Path Scoping

**Without `paths:`** — Rule loads at session start, applies to all files (same cost as CLAUDE.md).

**With `paths:`** — Rule loads lazily when Claude reads files matching the patterns. Zero context cost until triggered.

**Supported glob patterns:**

| Pattern | Matches |
|---------|---------|
| `**/*.ts` | All TypeScript files in any directory |
| `src/**/*` | Everything under `src/` |
| `*.md` | Markdown files in the directory only |
| `src/**/*.{ts,tsx}` | Brace expansion for multiple extensions |
| `tests/**/*.test.ts` | Specific naming patterns |

Wildcards: `*` (anything except `/`), `**` (across directories), `?` (single char), `[abc]` (character class), `{a,b}` (alternation).

### Rules vs CLAUDE.md

| Aspect | Rules | CLAUDE.md |
|--------|-------|-----------|
| Location | `.claude/rules/*.md` | `./CLAUDE.md`, `~/.claude/CLAUDE.md` |
| Path scoping | Yes (`paths:` frontmatter) | No |
| Lazy loading | Yes (path-scoped rules) | No (always at startup) |
| Organization | Multiple modular files | Single file (or imports) |
| Context cost | Zero until triggered (if path-scoped) | Always costs tokens |
| Use case | File-type or directory-specific rules | Universal project standards |

**Priority**: Rules and CLAUDE.md at the same scope level have **equal priority**. All are concatenated as context.

### Organizing Rules for Monorepos

```
project/
├── .claude/rules/
│   ├── commits.md              # Unconditional — always loaded
│   └── testing.md              # Unconditional — always loaded
├── packages/
│   └── .claude/rules/
│       ├── patterns.md         # paths: */src/**/*.py — lazy
│       ├── philosophy.md       # paths: */src/**/*.py — lazy
│       └── uv.md              # paths: */pyproject.toml — lazy
```

Rules in nested `.claude/rules/` directories are discovered when Claude's working context includes that subtree. Path-scoped rules within only trigger when matching files are accessed.

### InstructionsLoaded Hook

Track when rules/CLAUDE.md load with the `InstructionsLoaded` event:

```json
{
  "InstructionsLoaded": [{
    "matcher": "path_glob_match",
    "hooks": [{
      "type": "command",
      "command": "echo 'Rule loaded: $INSTRUCTION_FILE'"
    }]
  }]
}
```

Load reasons: `session_start`, `nested_traversal`, `path_glob_match`, `include`, `compact`.

---

## 3. Skills Design

### SKILL.md Frontmatter Schema

```yaml
---
name: my-skill                        # Defaults to directory name
description: What this skill does     # Keywords help auto-invocation
argument-hint: [issue-number]         # Autocomplete hint for user
paths:                                # Glob patterns for auto-activation
  - "src/api/**/*.ts"
  - "tests/**"
user-invocable: true                  # Show in /menu (default: true)
disable-model-invocation: false       # Prevent Claude auto-invoke (default: false)
allowed-tools:                        # Restrict available tools
  - Read
  - Grep
  - Bash(git:*)
model: claude-sonnet-4-6              # Override session model
effort: medium                        # Override session effort
context: fork                         # Run in forked subagent
agent: Explore                        # Subagent type
shell: bash                           # bash (default) or powershell
---
```

### Path Scoping

When `paths` is set, the skill activates automatically **only** when working with files matching the patterns:

```yaml
paths:
  - "src/api/**/*.ts"      # API routes
  - "src/handlers/**/*.ts"  # Request handlers
```

**Without paths**: Skill applies to all files.

**Monorepo pattern**: Nest `.claude/skills/` per package. Claude auto-discovers from current directory and parents:

```
packages/frontend/.claude/skills/react-patterns/SKILL.md
packages/backend/.claude/skills/api-handler/SKILL.md
```

### Invocation Control Matrix

| `user-invocable` | `disable-model-invocation` | /menu? | Claude auto-invokes? | Use case |
|-------------------|---------------------------|--------|---------------------|----------|
| `true` (default) | `false` (default) | Yes | Yes | Standard skill |
| `true` | `true` | Yes | No | Side-effect workflows (deploy, commit) |
| `false` | `false` | No | Yes | Background knowledge |
| `false` | `true` | No | No | Not useful |

**When `disable-model-invocation: true`:**
- Skill description is **NOT** loaded into context
- Full content loads only when user manually invokes with `/name`
- Use for: deployments, commits, side-effect workflows where timing is critical

**When `user-invocable: false`:**
- Description **IS** always in context (Claude knows about it)
- Does NOT appear in `/` menu
- Claude can invoke automatically when relevant
- Use for: background knowledge, legacy system context, reference material

### Progressive Disclosure

1. **Session start**: Only skill **descriptions** loaded (budget: ~1% of context window, minimum 8000 chars)
2. **On invocation**: Full skill content loaded
3. **Supporting files**: Reference from SKILL.md for on-demand loading

```markdown
For complete API details, see [reference.md](reference.md)
For examples, see [examples.md](examples.md)
```

Descriptions are truncated at 250 chars in listings. Write descriptions that front-load keywords.

### Allowed-Tools Restrictions

Restrict what tools are available when a skill is active:

```yaml
allowed-tools:
  - Read
  - Grep
  - Bash(git:*)         # Only git commands
```

Formats:
- Single: `allowed-tools: Read`
- Comma-separated: `allowed-tools: Read, Write, Edit`
- YAML list with patterns: `Bash(npm:*)`, `Bash(docker:*)`
- MCP tools: `mcp__github__search_repositories`

### Dynamic Content in Skills

Inject command output into skill content with `` !`command` ``:

```markdown
Current PR diff: !`gh pr diff`
PR comments: !`gh pr view --comments`
```

**String substitutions:**

| Variable | Description |
|----------|-------------|
| `$ARGUMENTS` | All arguments passed to skill |
| `$0`, `$1`, ... | Specific arguments by index |
| `${CLAUDE_SESSION_ID}` | Current session ID |
| `${CLAUDE_SKILL_DIR}` | Directory containing SKILL.md |

### Skills Interaction with Rules and CLAUDE.md

- CLAUDE.md and rules are in context **before** any skill loads
- When a skill is invoked, its content is **added** to existing context
- Skills cannot override CLAUDE.md or rules — everything is additive
- Skills with `context: fork` run in a subagent that gets its own copy of CLAUDE.md + preloaded skills
- Scope precedence: Enterprise > Personal > Project > Plugin

---

## 4. Hooks as Guardrails

### Hook Events Reference

**Pre-execution:**
- `SessionStart` — Session begins/resumes
- `InstructionsLoaded` — CLAUDE.md or rules loaded
- `UserPromptSubmit` — User submits prompt (before processing)

**Tool lifecycle:**
- `PreToolUse` — Before tool execution (**can block**)
- `PermissionRequest` — Permission dialog about to show
- `PostToolUse` — After tool succeeds
- `PostToolUseFailure` — After tool fails

**Session:**
- `Stop` — Claude finishes responding
- `PreCompact` — Before context compaction
- `PostCompact` — After compaction

**Other:**
- `Notification` — Waiting for input/permission
- `SubagentStart` / `SubagentStop` — Agent lifecycle
- `FileChanged` — Watched file changes
- `ConfigChange` — Settings/skills file changes

### Hook Types — Decision Framework

| Type | Best for | Timeout | Cost |
|------|----------|---------|------|
| `command` | Deterministic shell operations, fast checks | 10-30s | Low (no LLM) |
| `prompt` | Yes/no decisions based on hook input data | 30s | Medium (single LLM call) |
| `agent` | Verification requiring file reads or commands | 60s | High (LLM + tools) |
| `http` | External service logging, team audit | 10s | Network latency |

### PreToolUse — Blocking Dangerous Actions

```json
{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "command": "bash .claude/hooks/validate-bash.sh",
      "timeout": 10
    }]
  }]
}
```

**Decision responses:**
- `exit 0` or `"permissionDecision": "allow"` — Allow the tool
- `exit 2` or `"permissionDecision": "deny"` — Block with reason
- `"permissionDecision": "ask"` — Show permission prompt normally

**Important**: Hook returning `"allow"` does NOT override permission deny rules. Hooks can tighten restrictions but not loosen past what permission rules allow.

**Rewriting tool input:**
```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "updatedInput": { "command": "modified-command" }
  }
}
```

### PostToolUse — Auto-formatting and Logging

```json
{
  "PostToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{
      "type": "command",
      "command": "prettier --write $TOOL_INPUT_FILE_PATH",
      "timeout": 30
    }]
  }]
}
```

Cannot undo the action (already executed), but can inject context or block further work.

### Stop — Task Completion Verification

```json
{
  "Stop": [{
    "matcher": "",
    "hooks": [{
      "type": "command",
      "command": ".claude/hooks/check-complete.sh",
      "timeout": 45
    }]
  }]
}
```

**Anti-loop pattern** (critical — Stop fires on every response):

```bash
#!/bin/bash
INPUT=$(cat)

# Check if this hook already triggered to avoid infinite loops
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # Allow stop — already verified once
fi

# Your verification logic
if ! all_tasks_done; then
  echo "Tasks X and Y still incomplete" >&2
  exit 2  # Block stop
fi

exit 0  # Allow stop
```

### PermissionRequest — Auto-approving Safe Patterns

```json
{
  "PermissionRequest": [{
    "matcher": "Read",
    "hooks": [{
      "type": "command",
      "command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\"}}}'"
    }]
  }]
}
```

Keep matchers **narrow**. An empty matcher auto-approves everything (dangerous).

### The `if` Field — Argument-Level Filtering

Finer than `matcher` (which only matches tool name). The `if` field matches tool arguments:

```json
{
  "PreToolUse": [{
    "matcher": "Bash",
    "hooks": [{
      "type": "command",
      "if": "Bash(git *)",
      "command": "check-git-policy.sh"
    }]
  }]
}
```

When `if` doesn't match, the hook process **doesn't spawn** (zero overhead). Uses permission rule syntax: `Bash(git:*)`, `Edit(*.ts)`, etc.

### PreCompact / PostCompact — Preserving Context

```json
{
  "PostCompact": [{
    "matcher": "auto",
    "hooks": [{
      "type": "command",
      "command": "echo 'Reminder: use uv, not pip. Current task: refactor auth.'"
    }]
  }]
}
```

PostCompact output goes directly to Claude's context after compaction. Use this to re-inject critical reminders that might be lost.

### Settings Hierarchy for Hooks

Hooks merge across scopes (all matching hooks run):

1. **Managed policy** (highest, cannot override)
2. **Project local** (`.claude/settings.local.json`)
3. **Project shared** (`.claude/settings.json`)
4. **User** (`~/.claude/settings.json`)
5. **Plugin** (`<plugin>/hooks/hooks.json`)
6. **Skill/agent frontmatter** (while active)

When multiple scopes define hooks for the same event, **all hooks run**. For conflicting decisions, most restrictive wins (deny > ask > allow).

### Performance Considerations

**High-frequency hooks** (run often — keep fast):
- `PreToolUse` — fires before every tool call
- `PostToolUse` — fires after every tool call
- Use `command` type + `if` field to minimize overhead

**Low-frequency hooks** (run rarely — can be heavier):
- `SessionStart` — once per session
- `Stop` — once per response
- `PreCompact` / `PostCompact` — on compaction events

**Optimization:**
- Use `if` field to skip hook process on non-matching arguments
- Use `command` type (fast) over `agent` type (slow, uses model tokens)
- Mark expensive hooks `"async": true` to not block

---

## 5. Context Window Management

### What Gets Loaded and When

**At session start** (always in context):
1. System prompt (~4,200 tokens)
2. Auto memory — first 200 lines or 25KB of `MEMORY.md`
3. Environment info (CWD, platform, git status, recent commits)
4. User CLAUDE.md
5. Project CLAUDE.md
6. Unconditional rules (`.claude/rules/` without `paths:`)
7. Skill descriptions only (~1% of context window budget)
8. MCP tool names (schemas loaded on-demand)

**During session** (lazy-loaded):
- Path-scoped rules — when matching files are read
- Subdirectory CLAUDE.md — when accessing files in that directory
- Full skill content — when a skill is invoked
- MCP tool schemas — when Claude considers using a tool

### Token Budget Awareness

| Component | Approximate Cost | When |
|-----------|-----------------|------|
| System prompt | ~4,200 tokens | Always |
| Auto memory | Variable (capped 25KB) | Always |
| Environment | ~280 tokens | Always |
| CLAUDE.md (typical) | 500-2,000 tokens | Always |
| Each unconditional rule | 200-400 tokens | Always |
| Skill descriptions (all) | ~450 tokens total | Always |
| Each path-scoped rule | 200-400 tokens | When triggered |
| Full skill content | Variable | When invoked |

**Strategy**: Move instructions into path-scoped rules to defer their context cost until relevant files are accessed.

### Compaction Behavior

When context fills up, Claude Code compacts:

**Preserved**: System prompt, CLAUDE.md (re-read from disk), auto memory, rules, your intent, key decisions
**Dropped**: Verbatim conversation, full tool outputs, intermediate reasoning
**Lost**: Skill descriptions (only invoked skills survive)

### Strategies for Clean Context

1. **Path-scoped rules** — Instructions only load when relevant files are accessed
2. **Skills with `disable-model-invocation: true`** — No description in context until user invokes
3. **Subagents for exploration** — Heavy file reads happen in a separate context window; only the summary returns
4. **Targeted reads** — Read specific file + line range instead of full files
5. **PostCompact hooks** — Re-inject critical reminders after compaction
6. **CLAUDE.md imports** — Keep main file concise, import details from supporting files

---

## 6. Project Configuration Patterns

### `.claude/settings.json` — Shared Team Config

```json
{
  "permissions": {
    "allow": [
      "Bash(prek *)",
      "Bash(uv run pytest *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)"
    ]
  },
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "ruff format --quiet $TOOL_INPUT_FILE_PATH",
        "timeout": 10
      }]
    }]
  },
  "env": {
    "UV_PYTHON": "3.12"
  }
}
```

**Commit this to git.** Team members get shared permissions, hooks, and environment.

### `.claude/settings.local.json` — Personal Overrides

```json
{
  "permissions": {
    "allow": ["Bash(docker *)"]
  },
  "model": "claude-opus-4-6"
}
```

**Add to `.gitignore`.** Personal preferences that don't affect the team.

### `.mcp.json` — MCP Server Configuration

```json
{
  "mcpServers": {
    "github": {
      "command": "node",
      "args": ["path/to/github-server.js"],
      "type": "stdio"
    },
    "postgres": {
      "url": "http://localhost:3000/mcp",
      "type": "http"
    }
  }
}
```

Lives at project root (committed) or `~/.claude.json` (personal).

### Settings Precedence

From highest to lowest:
1. **Managed** (enterprise IT, cannot be overridden)
2. **CLI arguments** (temporary session overrides)
3. **Local project** (`.claude/settings.local.json`)
4. **Shared project** (`.claude/settings.json`)
5. **User** (`~/.claude/settings.json`)

Array settings (like `permissions.allow`) **merge** across scopes (concatenate + deduplicate), not replace.

---

## 7. Real-World Patterns

### Monorepo Setup

```
monorepo/
├── CLAUDE.md                          # Workspace-wide: build commands, architecture
├── .claude/
│   ├── settings.json                  # Shared permissions and hooks
│   ├── rules/
│   │   └── commits.md                 # Unconditional: commit conventions
│   └── skills/
│       └── deploy/SKILL.md            # Manual-only deployment skill
├── packages/
│   ├── .claude/
│   │   └── rules/
│   │       ├── patterns.md            # paths: */src/**/*.py
│   │       └── uv.md                  # paths: */pyproject.toml
│   ├── frontend/
│   │   ├── CLAUDE.md                  # React conventions (lazy-loaded)
│   │   └── .claude/skills/
│   │       └── react-patterns/SKILL.md
│   └── backend/
│       ├── CLAUDE.md                  # API conventions (lazy-loaded)
│       └── .claude/skills/
│           └── api-handler/SKILL.md
```

**How it works:**
- Root `CLAUDE.md` always in context (workspace build commands)
- `commits.md` always in context (applies to all code)
- `patterns.md` loads only when editing Python source
- `packages/frontend/CLAUDE.md` loads when Claude reads frontend files
- React skill available only when working in frontend package

### CI/CD Quality Gates via Hooks

**`.claude/settings.json`:**
```json
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "ruff check --fix $TOOL_INPUT_FILE_PATH && ruff format $TOOL_INPUT_FILE_PATH",
        "timeout": 15
      }]
    }],
    "Stop": [{
      "matcher": "",
      "hooks": [{
        "type": "agent",
        "prompt": "Check if code was modified in this session. If so, verify tests pass by running: uv run pytest packages/ -v"
      }]
    }]
  }
}
```

### What to Commit vs. Keep Local

| Commit | Gitignore |
|--------|-----------|
| `.claude/settings.json` | `.claude/settings.local.json` |
| `.claude/rules/` | `CLAUDE.local.md` |
| `.claude/skills/` | Personal MCP configs |
| `.claude/hooks/` (scripts) | API keys / tokens |
| `CLAUDE.md` | `.mcp.json` (if contains secrets) |
| `.mcp.json` (if no secrets) | |

### Onboarding Pattern

A new developer clones the repo and runs `claude`. Automatically:

1. Project `CLAUDE.md` loads — they learn build commands, architecture, coding standards
2. Shared rules load — commit conventions, code style enforced
3. Shared permissions activate — safe commands pre-approved, dangerous ones blocked
4. Hooks engage — auto-formatting on edit, quality checks on stop
5. Skills available — `/deploy`, `/review-pr` ready to use
6. MCP servers connect — project-specific tools available

No manual setup required. Everything is in the committed `.claude/` directory.

---

## Interaction Map

How the pieces compose:

```
┌─────────────────────────────────────────────────────┐
│ Context Window                                       │
│                                                      │
│  ┌─────────────┐  ┌──────────────┐  ┌────────────┐ │
│  │ CLAUDE.md   │  │ Rules        │  │ Skills     │ │
│  │ (always)    │  │ (lazy/eager) │  │ (on-demand)│ │
│  └─────────────┘  └──────────────┘  └────────────┘ │
│                                                      │
│  All provide context (soft guidance)                 │
│  None enforce behavior (use hooks/settings for that) │
└─────────────────────────────────────────────────────┘
          │                    │
          ▼                    ▼
┌──────────────────┐  ┌──────────────────┐
│ settings.json    │  │ hooks            │
│ (hard enforce)   │  │ (hard enforce)   │
│                  │  │                  │
│ • permissions    │  │ • PreToolUse     │
│ • deny rules     │  │   (block actions)│
│ • sandbox        │  │ • PostToolUse    │
│                  │  │   (auto-format)  │
│ Cannot be        │  │ • Stop           │
│ overridden by    │  │   (verify tasks) │
│ CLAUDE.md or     │  │                  │
│ conversation     │  │ Exit codes and   │
│                  │  │ decisions are    │
│                  │  │ enforced         │
└──────────────────┘  └──────────────────┘
```

**Key principle**: CLAUDE.md, rules, and skills are **context** (soft guidance — Claude reads and usually follows, but no guarantee). Settings and hooks are **configuration** (hard enforcement — permissions block tools, hooks can deny actions regardless of Claude's intent).

For critical constraints, don't rely on CLAUDE.md alone. Use `permissions.deny` in settings.json or `PreToolUse` hooks for hard enforcement.

---

## 8. Custom Agents (`.claude/agents/`)

### File Format

Agents are markdown files with YAML frontmatter. Unlike skills (which are directories), agents are single `.md` files:

```
.claude/agents/
├── code-reviewer.md
├── test-writer.md
└── researcher.md
```

### Frontmatter Schema

```yaml
---
name: code-reviewer
description: |
  Use this agent when the user asks for code review. Examples:

  <example>
  Context: User wants feedback on a PR
  user: "Review this PR"
  assistant: "I'll use the code-reviewer agent."
  <commentary>
  Code review request triggers this agent.
  </commentary>
  </example>

model: inherit                    # sonnet, opus, haiku, inherit, or full model ID
color: blue                       # red, blue, green, yellow, purple, orange, pink, cyan
tools: ["Read", "Grep", "Glob"]  # Restrict available tools (inherit all if omitted)
disallowedTools: ["Write"]        # Deny specific tools
permissionMode: default           # default, acceptEdits, auto, dontAsk, bypassPermissions, plan
maxTurns: 50                      # Max agentic turns before stopping
skills: ["my-skill"]              # Skills injected into agent context at startup
mcpServers: {}                    # MCP servers scoped to this agent
hooks: {}                         # Hooks during agent lifecycle
memory: project                   # user, project, or local — persistent memory scope
background: false                 # Always run as background task
effort: medium                    # low, medium, high, max
isolation: worktree               # Git-isolated execution
initialPrompt: "Start analysis"  # Auto-submitted first turn
---

You are a code reviewer. Your core responsibilities:
1. Check for bugs and edge cases
2. Verify test coverage
3. Review naming and documentation
```

The markdown body below the frontmatter becomes the agent's **system prompt**.

### Agents vs Skills

| Aspect | Agent | Skill |
|--------|-------|-------|
| Context | **Separate context window** | Inline in main thread |
| System prompt | Custom per agent | None (injected into session) |
| File format | Single `.md` file | Directory with `SKILL.md` + supporting files |
| Tool restrictions | Per agent via `tools` field | Per skill via `allowed-tools` |
| Worktree isolation | Yes (`isolation: worktree`) | No |
| Path scoping | No | Yes (`paths:` frontmatter) |
| Invocation | Auto-delegation or `/agents` menu | `/skill-name` or auto |
| Supporting files | No — use `skills` field instead | Yes (reference.md, scripts/, etc.) |

### Discovery

- Auto-discovered from `.claude/agents/` at session start
- Scope priority: Managed > CLI > Project > User > Plugin
- Plugin agents use namespace: `plugin-name:agent-name`
- Plugin agents **cannot** define hooks or mcpServers (security restriction)

### When to Use Agents vs Skills

**Use agents when:**
- Task needs a separate context window (heavy exploration, large codebases)
- You want tool restrictions (read-only agent, no-bash agent)
- Task benefits from worktree isolation
- You need a custom system prompt that overrides default behavior

**Use skills when:**
- Task runs inline in the main conversation
- You need path scoping (activate only for certain files)
- You have supporting reference files
- You want progressive disclosure (description → full content)

---

## 9. Commands (`.claude/commands/`)

### Format

Commands are single markdown files — the simpler predecessor to skills:

```
.claude/commands/
├── review-pr.md
└── run-tests.md
```

Same frontmatter as skills (`description`, `allowed-tools`, `disable-model-invocation`, etc.) but **no supporting files** — everything in one `.md` file.

### Commands vs Skills

| Aspect | Command | Skill |
|--------|---------|-------|
| Structure | Single `.md` file | Directory with SKILL.md + supporting files |
| Supporting files | No | Yes (reference.md, scripts/, templates/) |
| Progressive disclosure | No (full content on invoke) | Yes (description → full content) |
| `${CLAUDE_SKILL_DIR}` | Not available | Available |
| Dynamic injection | `` !`command` `` works | `` !`command` `` works |

**Commands are NOT deprecated** but skills are recommended for new work. Both create `/name` shortcuts identically.

---

## 10. Plugin Structure

### Directory Layout

```
my-plugin/
├── .claude-plugin/
│   ├── plugin.json            # Manifest (optional but recommended)
│   └── marketplace.json       # Multi-plugin marketplace config
├── agents/                    # Subagent definitions
│   └── reviewer.md
├── skills/                    # Skills with supporting files
│   └── optimize/
│       ├── SKILL.md
│       └── references/
│           └── patterns.md
├── commands/                  # Legacy commands
│   └── deploy.md
├── hooks/
│   └── hooks.json             # Plugin hook definitions
├── references/                # Shared reference material
│   └── shared/
│       └── conventions.md
├── .mcp.json                  # Plugin MCP servers
├── bin/                       # Executables (added to PATH)
├── output-styles/             # Custom output styles
└── settings.json              # Default plugin settings
```

### plugin.json Schema

```json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "What this plugin does",
  "author": {"name": "Team", "email": "team@example.com"},
  "commands": ["./custom/cmd.md"],
  "agents": "./custom/agents/",
  "skills": "./custom/skills/",
  "hooks": "./hooks.json",
  "mcpServers": "./mcp.json",
  "outputStyles": "./styles/",
  "lspServers": "./.lsp.json",
  "userConfig": {
    "api_key": {
      "description": "Your API key",
      "sensitive": true
    }
  }
}
```

### Plugin Variables

| Variable | Resolves To | Use For |
|----------|-------------|---------|
| `${CLAUDE_PLUGIN_ROOT}` | Plugin installation directory | Ephemeral references (scripts, hooks, config) |
| `${CLAUDE_PLUGIN_DATA}` | `~/.claude/plugins/data/{plugin-id}/` | Persistent data (caches, installed deps) |
| `${CLAUDE_PROJECT_DIR}` | Project root directory | Accessing project files from hooks |

`CLAUDE_PLUGIN_ROOT` changes on plugin updates. `CLAUDE_PLUGIN_DATA` persists across updates.

### Plugin Hooks vs Project Hooks

- Plugin hooks run **only when the plugin is enabled**
- Project hooks **always run**
- Both execute in parallel for the same event
- Most restrictive decision wins (deny > ask > allow)
- Plugin hooks are defined in `hooks/hooks.json` (not in settings.json)

### References in Plugins

Plugins can bundle reference material that agents/skills access via `${CLAUDE_PLUGIN_ROOT}`:

```markdown
<!-- In an agent .md file -->
Read the conventions at ${CLAUDE_PLUGIN_ROOT}/references/shared/conventions.md
```

Reference files are **not auto-loaded** — they're read on-demand when an agent or skill needs them. This keeps them out of context until relevant.

---

## 11. Memory System

### Auto Memory

```
~/.claude/projects/<project-id>/memory/
├── MEMORY.md              # Index file (required)
├── debugging.md           # Topic files (auto-created)
├── architecture.md
└── decisions.md
```

**Loading**: First 200 lines OR 25KB of `MEMORY.md` loaded at session start. Topic files read on-demand.

**Storage**: Project-scoped by git repo path. All worktrees in same repo share one memory directory. Machine-local (not shared across machines).

**Configuration:**
```json
{
  "autoMemoryEnabled": true,
  "autoMemoryDirectory": "~/.claude/projects/<id>/memory/"
}
```

Toggle with `/memory` command or `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`.

### How Memory Interacts with Other Features

- MEMORY.md is **separate from** CLAUDE.md — both load at startup
- CLAUDE.md is deterministic (you control content); memory is Claude-managed
- Both survive compaction (re-read from disk)
- Memory is per-machine; CLAUDE.md is shared via git

### Agent Memory

Agents can have their own persistent memory via the `memory` frontmatter field:

```yaml
---
name: researcher
memory: project    # user, project, or local
---
```

Stored in `.claude/agent-memory/<agent-name>/MEMORY.md`.

---

## 12. References & Supporting Files

### In Skills

Skills can bundle arbitrary supporting files alongside SKILL.md:

```
my-skill/
├── SKILL.md                # Entry point (required)
├── reference.md            # Detailed API docs
├── examples.md             # Usage examples
├── scripts/
│   ├── validate.sh         # Executable scripts
│   └── helper.py
└── templates/
    └── pr-template.md      # Templates
```

**Loading behavior**: Supporting files are **NOT auto-loaded**. Claude reads them on-demand when SKILL.md references them:

```markdown
For complete patterns, see [reference.md](reference.md)
Run validation: !`bash ${CLAUDE_SKILL_DIR}/scripts/validate.sh`
```

This is the key progressive disclosure mechanism — SKILL.md is concise, details live in supporting files.

### In Plugins

Plugins use a `references/` directory for shared material accessible by all agents/skills in the plugin:

```
plugin/
├── references/
│   ├── shared/
│   │   ├── conventions.md
│   │   └── pr-preparation.md
│   ├── async/
│   │   └── guide.md
│   └── memory/
│       └── guide.md
├── agents/
│   └── optimizer.md        # References: ${CLAUDE_PLUGIN_ROOT}/references/shared/conventions.md
└── skills/
    └── optimize/SKILL.md   # References: ${CLAUDE_PLUGIN_ROOT}/references/async/guide.md
```

Referenced via `${CLAUDE_PLUGIN_ROOT}/references/...` in agent/skill content. Not auto-loaded — read on-demand.

### In CLAUDE.md (@ Imports)

```markdown
# Project Guide

@docs/architecture.md
@docs/api-reference.md

## Quick Start
...
```

Imported files expand at session start (not lazy). Recursive up to 5 levels.

---

## 13. Other Features

### Handoffs (`.claude/handoffs/`)

Session continuity mechanism:
- `/handoff` saves current session state to `.claude/handoffs/latest.md`
- New session can restore context from handoff
- Gitignored — session-specific, not shared

### .worktreeinclude

Lists gitignored files that should be copied into git worktrees:

```
.env
.env.local
config/secrets.json
```

Syntax follows `.gitignore` patterns. Ensures worktree-isolated agents have access to necessary config files.

### Additional Directories (`--add-dir`)

```bash
claude --add-dir ../shared-lib
```

**What loads from `--add-dir`:**
- `.claude/skills/` — auto-discovered
- Files — read access

**What does NOT load:**
- CLAUDE.md (unless `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1`)
- Agents, commands, hooks, MCP servers, output styles

### Output Styles

Custom response formatting in `~/.claude/output-styles/` or `.claude/output-styles/`:

```yaml
---
description: Concise teaching style
keep-coding-instructions: true
---

Be concise. Lead with code, follow with brief explanation.
Use bullet points. No preamble.
```

Selected via `/config` or `outputStyle` in settings.json.

### Environment Variables in Hooks/Skills

| Variable | Available In | Purpose |
|----------|-------------|---------|
| `${CLAUDE_SESSION_ID}` | Skills, hooks | Current session ID |
| `${CLAUDE_SKILL_DIR}` | Skills only | Skill directory path |
| `${CLAUDE_PROJECT_DIR}` | Hooks, skills | Project root |
| `${CLAUDE_PLUGIN_ROOT}` | Plugin content | Plugin install dir |
| `${CLAUDE_PLUGIN_DATA}` | Plugin content | Persistent plugin data |
| `${CLAUDE_ENV_FILE}` | Hooks only | Write env vars that persist across tool calls |
| `$ARGUMENTS`, `$0`, `$1` | Skills | Skill invocation arguments |

### claudeMdExcludes

Skip specific CLAUDE.md files in monorepos:

```json
{
  "claudeMdExcludes": [
    "**/node_modules/**/CLAUDE.md",
    "vendor/**/CLAUDE.md"
  ]
}
```

Glob patterns matched against absolute paths. Managed CLAUDE.md cannot be excluded.

---

## Complete Discovery & Loading Sequence

When Claude Code starts a session:

```
1. Load managed settings + managed CLAUDE.md (cannot exclude)
2. Walk up directory tree from CWD:
   └─ Load CLAUDE.md + CLAUDE.local.md at each level
3. Discover .claude/rules/*.md:
   ├─ Unconditional rules → load immediately
   └─ Path-scoped rules → register for lazy loading
4. Load auto memory (first 200 lines / 25KB of MEMORY.md)
5. Enumerate skills (descriptions only, ~1% context budget)
6. Enumerate agents (descriptions for delegation)
7. Load MCP server configs (.mcp.json)
8. Register hooks from all scopes
9. Session begins

During session:
├─ Path-scoped rules fire when matching files accessed
├─ Subdirectory CLAUDE.md loads when Claude reads files there
├─ Full skill content loads on invocation
├─ MCP tool schemas load when Claude considers using a tool
├─ Hooks fire on their respective events
└─ Compaction re-reads CLAUDE.md, memory, rules from disk
```

---

## Complete Feature Matrix

| Feature | Location | Load Time | Path Scoping | Auto-discovered |
|---------|----------|-----------|--------------|-----------------|
| CLAUDE.md | Project root, `~/.claude/` | Startup | No | Yes (walk up) |
| CLAUDE.local.md | Project root | Startup | No | Yes |
| Rules (unconditional) | `.claude/rules/` | Startup | No | Yes (recursive) |
| Rules (path-scoped) | `.claude/rules/` | On file access | Yes (`paths:`) | Yes (recursive) |
| Skills | `.claude/skills/*/` | Description: startup; Full: on invoke | Yes (`paths:`) | Yes (nested) |
| Commands | `.claude/commands/` | On invoke | No | Yes |
| Agents | `.claude/agents/` | Description: startup; Full: on delegate | No | Yes |
| Hooks | `settings.json`, plugin | On event | Via `matcher` + `if` | No (configured) |
| Auto memory | `~/.claude/projects/` | Startup (25KB cap) | No | Auto-created |
| MCP servers | `.mcp.json` | Startup | No | Yes |
| Output styles | `.claude/output-styles/` | Startup | No | Yes |
| Plugin refs | `plugin/references/` | On demand | No | No (referenced) |
| Skill refs | `skill-dir/` files | On demand | No | No (referenced) |
