Complete reference for Claude Code hooks, settings, MCP servers, and practical memory augmentation patterns.
27 total events (source-verified from src/entrypoints/sdk/coreTypes.ts):
| Event | When It Fires | What It Blocks |
|---|---|---|
PreToolUse | After Claude creates tool params, before execution | The tool call |
PermissionRequest | When a permission prompt would be shown | Denies permission |
UserPromptSubmit | When user submits a prompt | Blocks and erases prompt |
Stop | When Claude is about to stop | Prevents stopping |
SubagentStop | When a subagent is about to stop | Prevents subagent stop |
TaskCreated | When a task is created | Rolls back creation |
TaskCompleted | When a task completes | Prevents completion |
ConfigChange | When config is modified | Blocks config change |
Elicitation | When MCP elicitation is requested | Denies elicitation |
WorktreeCreate | When worktree creation is requested | Fails creation |
TeammateIdle | When a teammate goes idle | Continues teammate |
| Event | When It Fires |
|---|---|
PostToolUse | After a tool executes successfully |
PostToolUseFailure | After a tool execution fails |
SessionStart | On startup, resume, clear, or compact |
SessionEnd | On clear, resume, logout, exit |
Notification | On permission_prompt, idle_prompt, auth_success |
SubagentStart | When a subagent starts |
CwdChanged | When working directory changes |
FileChanged | When a watched file changes (by basename) |
PreCompact / PostCompact | Before/after compaction |
InstructionsLoaded | When instruction files load |
WorktreeRemove | When worktree is removed |
Setup | On init or maintenance (matcher: init or maintenance) |
PermissionDenied | After permission is denied (exit 2 enables retry) |
ElicitationResult | When MCP elicitation result arrives |
StopFailure | On rate_limit, auth_failed, billing_error, etc. |
| Type | Communication | Async? | Default Timeout |
|---|---|---|---|
command | stdin/stdout/exit codes | Yes (async: true) | 600s |
http | HTTP POST / response body | Implicit | 30s |
prompt | stdin to LLM, JSON back | No | 30s |
agent | Subagent with tools | No | 60s |
Matchers are regex patterns. What they match depends on the event:
| Event | Matches Against | Examples |
|---|---|---|
| Tool events | tool_name | Bash, Edit|Write, mcp__.* |
| SessionStart | Session source | startup, resume, clear, compact |
| SessionEnd | End reason | clear, resume, logout |
| Notification | Notification type | permission_prompt, idle_prompt |
| StopFailure | Error type | rate_limit, billing_error |
| InstructionsLoaded | Load reason | session_start, compact |
if Field (source-verified)Uses permission rule syntax for pre-execution filtering: "if": "Bash(git *)". Key differences from matcher:
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest)if conditions are distinct even if otherwise identicalAll hooks receive a common envelope:
{
"session_id": "abc123",
"transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
"cwd": "/current/working/directory",
"permission_mode": "default",
"hook_event_name": "PreToolUse"
}
Tool events additionally include tool_name, tool_input, and tool_use_id. PostToolUse also includes tool_response.
{
"continue": true,
"stopReason": "Build failed",
"suppressOutput": false,
"systemMessage": "Warning text",
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow|deny|ask",
"permissionDecisionReason": "explanation",
"updatedInput": { "command": "modified command" },
"additionalContext": "context for Claude"
}
}
| Code | Effect |
|---|---|
| 0 | Success. Stdout parsed for JSON output. Proceed. |
| 2 | Block the action. Stderr shown as feedback to Claude. |
| Other | Non-blocking error. Stderr in verbose mode only. |
SessionStart and UserPromptSubmit hooks, anything in the additionalContext field is added to Claude's context. This is how you inject memory content that the harness wouldn't otherwise load.
SessionStart hooks can return three special fields in hookSpecificOutput:
additionalContext — injected into Claude's contextinitialUserMessage — sets the first user messagewatchPaths — array of absolute file paths to monitor for FileChanged events{
"hooks": {
"SessionStart": [{
"matcher": "startup",
"hooks": [{
"type": "command",
"command": "/path/to/memory-router.sh",
"timeout": 5000
}]
}]
}
}
{
"hooks": {
"SessionStart": [{
"matcher": "compact",
"hooks": [{
"type": "command",
"command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"Reminder: always verify claims before acting on them.\"}}'"
}]
}]
}
}
The $CLAUDE_ENV_FILE mechanism lets SessionStart hooks persist environment variables across the session:
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export PROJECT_TYPE=svelte' >> "$CLAUDE_ENV_FILE"
fi
/etc/claude-code/managed-settings.json (cannot be overridden)--model, --permission-mode, etc..claude/settings.local.json (personal, not committed).claude/settings.json (committed, shared)~/.claude/settings.json (personal, all projects)| Key | Purpose |
|---|---|
autoMemoryEnabled | Toggle auto memory (default: true when unset) |
autoMemoryDirectory | Custom path (supports ~/). Ignored in projectSettings for security. |
autoDreamEnabled | User override for dream consolidation scheduling |
claudeMdExcludes | Glob patterns to skip CLAUDE.md files in monorepos |
includeGitInstructions | Include built-in git instructions (default: true) |
disableAllHooks | Kill switch for all hooks |
| Rule | Effect |
|---|---|
Bash | Matches all Bash commands |
Bash(npm run *) | Commands starting with npm run |
Read(./.env) | Reading .env file |
Edit(./src/**) | Edits to any file under src/ |
WebFetch(domain:example.com) | Fetches to example.com |
// ~/.claude/.mcp.json (user scope)
{
"mcpServers": {
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"],
"env": { "MEMORY_DIR": "/home/visar/.claude/semantic-memory" }
}
}
}
| Server | Backend | Features |
|---|---|---|
@modelcontextprotocol/server-memory | JSONL files | Official, simple, persistent KV store |
mcp-memory-keeper | File-based | Persistent context management for Claude Code |
mcp-memory-service | Knowledge graph | Autonomous consolidation, REST API |
memorious-mcp | ChromaDB (local) | Semantic search, store/recall/forget |
mcp-server-qdrant | Qdrant | Official Qdrant MCP, semantic memory |
Tool definitions are deferred by default — only tool names consume context until used. Check per-server context costs with /mcp.
# ~/.claude/rules/svelte-conventions.md
---
paths:
- "**/+page.svelte"
- "**/+layout.svelte"
- "**/*.svelte"
---
# Svelte 5 Rules
- Never use $: reactive statements (Svelte 4 syntax)
- Use $state, $derived, $effect runes
- Never call imperative APIs inside $effect
- Read svelte5-pitfalls.md for full list
# ~/.claude/rules/deploy-safety.md
---
paths:
- "**/deploy.sh"
- "**/Dockerfile"
- "**/.github/workflows/**"
---
# Deployment Rules
- Read hetzner-deploy.md before any deploy changes
- Always test locally before pushing
#!/bin/bash
# Inject git state as context
CONTEXT="Current branch: $(git branch --show-current 2>/dev/null)"
CONTEXT="$CONTEXT\nRecent commits:\n$(git log --oneline -5 2>/dev/null)"
CONTEXT="$CONTEXT\nChanged files:\n$(git diff --name-only 2>/dev/null)"
jq -n --arg ctx "$CONTEXT" '{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": $ctx
}
}'
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path')
PROTECTED=('.env' 'package-lock.json' '.git/')
for p in "${PROTECTED[@]}"; do
if [[ "$FILE" == *"$p"* ]]; then
echo "Blocked: $FILE matches protected pattern $p" >&2
exit 2
fi
done
exit 0
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path')
case "$FILE" in
*.ts|*.tsx|*.js|*.jsx) npx prettier --write "$FILE" ;;
*.py) black "$FILE" ;;
esac
exit 0
#!/bin/bash
# Inject universal rules that apply to every coding task
RULES="ALWAYS-ON RULES:
1. One fix at a time - only implement the specific approved change
2. Verify claims - label uncertain statements as 'Claim:' and offer to verify
3. Evidence first - debug from logs/data, never speculation
4. No magic strings - use constants or enums for property checks
5. Timebox debugging to ~1h, then build a minimal reproduction"
jq -n --arg ctx "$RULES" '{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": $ctx
}
}'