Initial release v3.3.8

- Hook system for customization
- Documentation and installation scripts
- Multi-platform support via GitHub releases
- Binaries available for Windows, Linux (x64/ARM64), macOS (Intel/Apple Silicon)

Generated with Claude Code via Happy
This commit is contained in:
thedotmack
2025-09-06 19:34:53 +00:00
commit 598369e894
26 changed files with 5547 additions and 0 deletions
+787
View File
@@ -0,0 +1,787 @@
# Hooks reference
> This page provides reference documentation for implementing hooks in Claude Code.
<Tip>
For a quickstart guide with examples, see [Get started with Claude Code hooks](/en/docs/claude-code/hooks-guide).
</Tip>
## Configuration
Claude Code hooks are configured in your [settings files](/en/docs/claude-code/settings):
* `~/.claude/settings.json` - User settings
* `.claude/settings.json` - Project settings
* `.claude/settings.local.json` - Local project settings (not committed)
* Enterprise managed policy settings
### Structure
Hooks are organized by matchers, where each matcher can have multiple hooks:
```json
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
```
* **matcher**: Pattern to match tool names, case-sensitive (only applicable for
`PreToolUse` and `PostToolUse`)
* Simple strings match exactly: `Write` matches only the Write tool
* Supports regex: `Edit|Write` or `Notebook.*`
* Use `*` to match all tools. You can also use empty string (`""`) or leave
`matcher` blank.
* **hooks**: Array of commands to execute when the pattern matches
* `type`: Currently only `"command"` is supported
* `command`: The bash command to execute (can use `$CLAUDE_PROJECT_DIR`
environment variable)
* `timeout`: (Optional) How long a command should run, in seconds, before
canceling that specific command.
For events like `UserPromptSubmit`, `Notification`, `Stop`, and `SubagentStop`
that don't use matchers, you can omit the matcher field:
```json
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/prompt-validator.py"
}
]
}
]
}
}
```
### Project-Specific Hook Scripts
You can use the environment variable `CLAUDE_PROJECT_DIR` (only available when
Claude Code spawns the hook command) to reference scripts stored in your project,
ensuring they work regardless of Claude's current directory:
```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-style.sh"
}
]
}
]
}
}
```
## Hook Events
### PreToolUse
Runs after Claude creates tool parameters and before processing the tool call.
**Common matchers:**
* `Task` - Subagent tasks (see [subagents documentation](/en/docs/claude-code/sub-agents))
* `Bash` - Shell commands
* `Glob` - File pattern matching
* `Grep` - Content search
* `Read` - File reading
* `Edit`, `MultiEdit` - File editing
* `Write` - File writing
* `WebFetch`, `WebSearch` - Web operations
### PostToolUse
Runs immediately after a tool completes successfully.
Recognizes the same matcher values as PreToolUse.
### Notification
Runs when Claude Code sends notifications. Notifications are sent when:
1. Claude needs your permission to use a tool. Example: "Claude needs your
permission to use Bash"
2. The prompt input has been idle for at least 60 seconds. "Claude is waiting
for your input"
### UserPromptSubmit
Runs when the user submits a prompt, before Claude processes it. This allows you
to add additional context based on the prompt/conversation, validate prompts, or
block certain types of prompts.
### Stop
Runs when the main Claude Code agent has finished responding. Does not run if
the stoppage occurred due to a user interrupt.
### SubagentStop
Runs when a Claude Code subagent (Task tool call) has finished responding.
### SessionEnd
Runs when a Claude Code session ends. Useful for cleanup tasks, logging session
statistics, or saving session state.
The `reason` field in the hook input will be one of:
* `clear` - Session cleared with /clear command
* `logout` - User logged out
* `prompt_input_exit` - User exited while prompt input was visible
* `other` - Other exit reasons
### PreCompact
Runs before Claude Code is about to run a compact operation.
**Matchers:**
* `manual` - Invoked from `/compact`
* `auto` - Invoked from auto-compact (due to full context window)
### SessionStart
Runs when Claude Code starts a new session or resumes an existing session (which
currently does start a new session under the hood). Useful for loading in
development context like existing issues or recent changes to your codebase.
**Matchers:**
* `startup` - Invoked from startup
* `resume` - Invoked from `--resume`, `--continue`, or `/resume`
* `clear` - Invoked from `/clear`
## Hook Input
Hooks receive JSON data via stdin containing session information and
event-specific data:
```typescript
{
// Common fields
session_id: string
transcript_path: string // Path to conversation JSON
cwd: string // The current working directory when the hook is invoked
// Event-specific fields
hook_event_name: string
...
}
```
### PreToolUse Input
The exact schema for `tool_input` depends on the tool.
```json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
}
}
```
### PostToolUse Input
The exact schema for `tool_input` and `tool_response` depends on the tool.
```json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
}
}
```
### Notification Input
```json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "Notification",
"message": "Task completed successfully"
}
```
### UserPromptSubmit Input
```json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}
```
### Stop and SubagentStop Input
`stop_hook_active` is true when Claude Code is already continuing as a result of
a stop hook. Check this value or process the transcript to prevent Claude Code
from running indefinitely.
```json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"hook_event_name": "Stop",
"stop_hook_active": true
}
```
### PreCompact Input
For `manual`, `custom_instructions` comes from what the user passes into
`/compact`. For `auto`, `custom_instructions` is empty.
```json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"hook_event_name": "PreCompact",
"trigger": "manual",
"custom_instructions": ""
}
```
### SessionStart Input
```json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"hook_event_name": "SessionStart",
"source": "startup"
}
```
### SessionEnd Input
```json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "SessionEnd",
"reason": "exit"
}
```
## Hook Output
There are two ways for hooks to return output back to Claude Code. The output
communicates whether to block and any feedback that should be shown to Claude
and the user.
### Simple: Exit Code
Hooks communicate status through exit codes, stdout, and stderr:
* **Exit code 0**: Success. `stdout` is shown to the user in transcript mode
(CTRL-R), except for `UserPromptSubmit` and `SessionStart`, where stdout is
added to the context.
* **Exit code 2**: Blocking error. `stderr` is fed back to Claude to process
automatically. See per-hook-event behavior below.
* **Other exit codes**: Non-blocking error. `stderr` is shown to the user and
execution continues.
<Warning>
Reminder: Claude Code does not see stdout if the exit code is 0, except for
the `UserPromptSubmit` hook where stdout is injected as context.
</Warning>
#### Exit Code 2 Behavior
| Hook Event | Behavior |
| ------------------ | ------------------------------------------------------------------ |
| `PreToolUse` | Blocks the tool call, shows stderr to Claude |
| `PostToolUse` | Shows stderr to Claude (tool already ran) |
| `Notification` | N/A, shows stderr to user only |
| `UserPromptSubmit` | Blocks prompt processing, erases prompt, shows stderr to user only |
| `Stop` | Blocks stoppage, shows stderr to Claude |
| `SubagentStop` | Blocks stoppage, shows stderr to Claude subagent |
| `PreCompact` | N/A, shows stderr to user only |
| `SessionStart` | N/A, shows stderr to user only |
| `SessionEnd` | N/A, shows stderr to user only |
### Advanced: JSON Output
Hooks can return structured JSON in `stdout` for more sophisticated control:
#### Common JSON Fields
All hook types can include these optional fields:
```json
{
"continue": true, // Whether Claude should continue after hook execution (default: true)
"stopReason": "string", // Message shown when continue is false
"suppressOutput": true, // Hide stdout from transcript mode (default: false)
"systemMessage": "string" // Optional warning message shown to the user
}
```
If `continue` is false, Claude stops processing after the hooks run.
* For `PreToolUse`, this is different from `"permissionDecision": "deny"`, which
only blocks a specific tool call and provides automatic feedback to Claude.
* For `PostToolUse`, this is different from `"decision": "block"`, which
provides automated feedback to Claude.
* For `UserPromptSubmit`, this prevents the prompt from being processed.
* For `Stop` and `SubagentStop`, this takes precedence over any
`"decision": "block"` output.
* In all cases, `"continue" = false` takes precedence over any
`"decision": "block"` output.
`stopReason` accompanies `continue` with a reason shown to the user, not shown
to Claude.
#### `PreToolUse` Decision Control
`PreToolUse` hooks can control whether a tool call proceeds.
* `"allow"` bypasses the permission system. `permissionDecisionReason` is shown
to the user but not to Claude.
* `"deny"` prevents the tool call from executing. `permissionDecisionReason` is
shown to Claude.
* `"ask"` asks the user to confirm the tool call in the UI.
`permissionDecisionReason` is shown to the user but not to Claude.
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow" | "deny" | "ask",
"permissionDecisionReason": "My reason here"
}
}
```
<Note>
The `decision` and `reason` fields are deprecated for PreToolUse hooks.
Use `hookSpecificOutput.permissionDecision` and
`hookSpecificOutput.permissionDecisionReason` instead. The deprecated fields
`"approve"` and `"block"` map to `"allow"` and `"deny"` respectively.
</Note>
#### `PostToolUse` Decision Control
`PostToolUse` hooks can provide feedback to Claude after tool execution.
* `"block"` automatically prompts Claude with `reason`.
* `undefined` does nothing. `reason` is ignored.
* `"hookSpecificOutput.additionalContext"` adds context for Claude to consider.
```json
{
"decision": "block" | undefined,
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Claude"
}
}
```
#### `UserPromptSubmit` Decision Control
`UserPromptSubmit` hooks can control whether a user prompt is processed.
* `"block"` prevents the prompt from being processed. The submitted prompt is
erased from context. `"reason"` is shown to the user but not added to context.
* `undefined` allows the prompt to proceed normally. `"reason"` is ignored.
* `"hookSpecificOutput.additionalContext"` adds the string to the context if not
blocked.
```json
{
"decision": "block" | undefined,
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "My additional context here"
}
}
```
#### `Stop`/`SubagentStop` Decision Control
`Stop` and `SubagentStop` hooks can control whether Claude must continue.
* `"block"` prevents Claude from stopping. You must populate `reason` for Claude
to know how to proceed.
* `undefined` allows Claude to stop. `reason` is ignored.
```json
{
"decision": "block" | undefined,
"reason": "Must be provided when Claude is blocked from stopping"
}
```
#### `SessionStart` Decision Control
`SessionStart` hooks allow you to load in context at the start of a session.
* `"hookSpecificOutput.additionalContext"` adds the string to the context.
* Multiple hooks' `additionalContext` values are concatenated.
```json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "My additional context here"
}
}
```
#### `SessionEnd` Decision Control
`SessionEnd` hooks run when a session ends. They cannot block session termination
but can perform cleanup tasks.
#### Exit Code Example: Bash Command Validation
```python
#!/usr/bin/env python3
import json
import re
import sys
# Define validation rules as a list of (regex pattern, message) tuples
VALIDATION_RULES = [
(
r"\bgrep\b(?!.*\|)",
"Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
),
(
r"\bfind\s+\S+\s+-name\b",
"Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
),
]
def validate_command(command: str) -> list[str]:
issues = []
for pattern, message in VALIDATION_RULES:
if re.search(pattern, command):
issues.append(message)
return issues
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")
if tool_name != "Bash" or not command:
sys.exit(1)
# Validate the command
issues = validate_command(command)
if issues:
for message in issues:
print(f"{message}", file=sys.stderr)
# Exit code 2 blocks tool call and shows stderr to Claude
sys.exit(2)
```
#### JSON Output Example: UserPromptSubmit to Add Context and Validation
<Note>
For `UserPromptSubmit` hooks, you can inject context using either method:
* Exit code 0 with stdout: Claude sees the context (special case for `UserPromptSubmit`)
* JSON output: Provides more control over the behavior
</Note>
```python
#!/usr/bin/env python3
import json
import sys
import re
import datetime
# Load input from stdin
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
prompt = input_data.get("prompt", "")
# Check for sensitive patterns
sensitive_patterns = [
(r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]
for pattern, message in sensitive_patterns:
if re.search(pattern, prompt):
# Use JSON output to block with a specific reason
output = {
"decision": "block",
"reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
}
print(json.dumps(output))
sys.exit(0)
# Add current time to context
context = f"Current time: {datetime.datetime.now()}"
print(context)
"""
The following is also equivalent:
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": context,
},
}))
"""
# Allow the prompt to proceed with the additional context
sys.exit(0)
```
#### JSON Output Example: PreToolUse with Approval
```python
#!/usr/bin/env python3
import json
import sys
# Load input from stdin
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# Example: Auto-approve file reads for documentation files
if tool_name == "Read":
file_path = tool_input.get("file_path", "")
if file_path.endswith((".md", ".mdx", ".txt", ".json")):
# Use JSON output to auto-approve the tool call
output = {
"decision": "approve",
"reason": "Documentation file auto-approved",
"suppressOutput": True # Don't show in transcript mode
}
print(json.dumps(output))
sys.exit(0)
# For other cases, let the normal permission flow proceed
sys.exit(0)
```
## Working with MCP Tools
Claude Code hooks work seamlessly with
[Model Context Protocol (MCP) tools](/en/docs/claude-code/mcp). When MCP servers
provide tools, they appear with a special naming pattern that you can match in
your hooks.
### MCP Tool Naming
MCP tools follow the pattern `mcp__<server>__<tool>`, for example:
* `mcp__memory__create_entities` - Memory server's create entities tool
* `mcp__filesystem__read_file` - Filesystem server's read file tool
* `mcp__github__search_repositories` - GitHub server's search tool
### Configuring Hooks for MCP Tools
You can target specific MCP tools or entire MCP servers:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}
```
## Examples
<Tip>
For practical examples including code formatting, notifications, and file protection, see [More Examples](/en/docs/claude-code/hooks-guide#more-examples) in the get started guide.
</Tip>
## Security Considerations
### Disclaimer
**USE AT YOUR OWN RISK**: Claude Code hooks execute arbitrary shell commands on
your system automatically. By using hooks, you acknowledge that:
* You are solely responsible for the commands you configure
* Hooks can modify, delete, or access any files your user account can access
* Malicious or poorly written hooks can cause data loss or system damage
* Anthropic provides no warranty and assumes no liability for any damages
resulting from hook usage
* You should thoroughly test hooks in a safe environment before production use
Always review and understand any hook commands before adding them to your
configuration.
### Security Best Practices
Here are some key practices for writing more secure hooks:
1. **Validate and sanitize inputs** - Never trust input data blindly
2. **Always quote shell variables** - Use `"$VAR"` not `$VAR`
3. **Block path traversal** - Check for `..` in file paths
4. **Use absolute paths** - Specify full paths for scripts (use
`$CLAUDE_PROJECT_DIR` for the project path)
5. **Skip sensitive files** - Avoid `.env`, `.git/`, keys, etc.
### Configuration Safety
Direct edits to hooks in settings files don't take effect immediately. Claude
Code:
1. Captures a snapshot of hooks at startup
2. Uses this snapshot throughout the session
3. Warns if hooks are modified externally
4. Requires review in `/hooks` menu for changes to apply
This prevents malicious hook modifications from affecting your current session.
## Hook Execution Details
* **Timeout**: 60-second execution limit by default, configurable per command.
* A timeout for an individual command does not affect the other commands.
* **Parallelization**: All matching hooks run in parallel
* **Deduplication**: Multiple identical hook commands are deduplicated automatically
* **Environment**: Runs in current directory with Claude Code's environment
* The `CLAUDE_PROJECT_DIR` environment variable is available and contains the
absolute path to the project root directory (where Claude Code was started)
* **Input**: JSON via stdin
* **Output**:
* PreToolUse/PostToolUse/Stop/SubagentStop: Progress shown in transcript (Ctrl-R)
* Notification/SessionEnd: Logged to debug only (`--debug`)
* UserPromptSubmit/SessionStart: stdout added as context for Claude
## Debugging
### Basic Troubleshooting
If your hooks aren't working:
1. **Check configuration** - Run `/hooks` to see if your hook is registered
2. **Verify syntax** - Ensure your JSON settings are valid
3. **Test commands** - Run hook commands manually first
4. **Check permissions** - Make sure scripts are executable
5. **Review logs** - Use `claude --debug` to see hook execution details
Common issues:
* **Quotes not escaped** - Use `\"` inside JSON strings
* **Wrong matcher** - Check tool names match exactly (case-sensitive)
* **Command not found** - Use full paths for scripts
### Advanced Debugging
For complex hook issues:
1. **Inspect hook execution** - Use `claude --debug` to see detailed hook
execution
2. **Validate JSON schemas** - Test hook input/output with external tools
3. **Check environment variables** - Verify Claude Code's environment is correct
4. **Test edge cases** - Try hooks with unusual file paths or inputs
5. **Monitor system resources** - Check for resource exhaustion during hook
execution
6. **Use structured logging** - Implement logging in your hook scripts
### Debug Output Example
Use `claude --debug` to see hook execution details:
```
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
```
Progress messages appear in transcript mode (Ctrl-R) showing:
* Which hook is running
* Command being executed
* Success/failure status
* Output or error messages
@@ -0,0 +1,202 @@
# Status line configuration
> Create a custom status line for Claude Code to display contextual information
Make Claude Code your own with a custom status line that displays at the bottom of the Claude Code interface, similar to how terminal prompts (PS1) work in shells like Oh-my-zsh.
## Create a custom status line
You can either:
* Run `/statusline` to ask Claude Code to help you set up a custom status line. By default, it will try to reproduce your terminal's prompt, but you can provide additional instructions about the behavior you want to Claude Code, such as `/statusline show the model name in orange`
* Directly add a `statusLine` command to your `.claude/settings.json`:
```json
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 0 // Optional: set to 0 to let status line go to edge
}
}
```
## How it Works
* The status line is updated when the conversation messages update
* Updates run at most every 300ms
* The first line of stdout from your command becomes the status line text
* ANSI color codes are supported for styling your status line
* Claude Code passes contextual information about the current session (model, directories, etc.) as JSON to your script via stdin
## JSON Input Structure
Your status line command receives structured data via stdin in JSON format:
```json
{
"hook_event_name": "Status",
"session_id": "abc123...",
"transcript_path": "/path/to/transcript.json",
"cwd": "/current/working/directory",
"model": {
"id": "claude-opus-4-1",
"display_name": "Opus"
},
"workspace": {
"current_dir": "/current/working/directory",
"project_dir": "/original/project/directory"
},
"version": "1.0.80",
"output_style": {
"name": "default"
},
"cost": {
"total_cost_usd": 0.01234,
"total_duration_ms": 45000,
"total_api_duration_ms": 2300,
"total_lines_added": 156,
"total_lines_removed": 23
}
}
```
## Example Scripts
### Simple Status Line
```bash
#!/bin/bash
# Read JSON input from stdin
input=$(cat)
# Extract values using jq
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}"
```
### Git-Aware Status Line
```bash
#!/bin/bash
# Read JSON input from stdin
input=$(cat)
# Extract values using jq
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
# Show git branch if in a git repo
GIT_BRANCH=""
if git rev-parse --git-dir > /dev/null 2>&1; then
BRANCH=$(git branch --show-current 2>/dev/null)
if [ -n "$BRANCH" ]; then
GIT_BRANCH=" | 🌿 $BRANCH"
fi
fi
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}$GIT_BRANCH"
```
### Python Example
```python
#!/usr/bin/env python3
import json
import sys
import os
# Read JSON from stdin
data = json.load(sys.stdin)
# Extract values
model = data['model']['display_name']
current_dir = os.path.basename(data['workspace']['current_dir'])
# Check for git branch
git_branch = ""
if os.path.exists('.git'):
try:
with open('.git/HEAD', 'r') as f:
ref = f.read().strip()
if ref.startswith('ref: refs/heads/'):
git_branch = f" | 🌿 {ref.replace('ref: refs/heads/', '')}"
except:
pass
print(f"[{model}] 📁 {current_dir}{git_branch}")
```
### Node.js Example
```javascript
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Read JSON from stdin
let input = '';
process.stdin.on('data', chunk => input += chunk);
process.stdin.on('end', () => {
const data = JSON.parse(input);
// Extract values
const model = data.model.display_name;
const currentDir = path.basename(data.workspace.current_dir);
// Check for git branch
let gitBranch = '';
try {
const headContent = fs.readFileSync('.git/HEAD', 'utf8').trim();
if (headContent.startsWith('ref: refs/heads/')) {
gitBranch = ` | 🌿 ${headContent.replace('ref: refs/heads/', '')}`;
}
} catch (e) {
// Not a git repo or can't read HEAD
}
console.log(`[${model}] 📁 ${currentDir}${gitBranch}`);
});
```
### Helper Function Approach
For more complex bash scripts, you can create helper functions:
```bash
#!/bin/bash
# Read JSON input once
input=$(cat)
# Helper functions for common extractions
get_model_name() { echo "$input" | jq -r '.model.display_name'; }
get_current_dir() { echo "$input" | jq -r '.workspace.current_dir'; }
get_project_dir() { echo "$input" | jq -r '.workspace.project_dir'; }
get_version() { echo "$input" | jq -r '.version'; }
get_cost() { echo "$input" | jq -r '.cost.total_cost_usd'; }
get_duration() { echo "$input" | jq -r '.cost.total_duration_ms'; }
get_lines_added() { echo "$input" | jq -r '.cost.total_lines_added'; }
get_lines_removed() { echo "$input" | jq -r '.cost.total_lines_removed'; }
# Use the helpers
MODEL=$(get_model_name)
DIR=$(get_current_dir)
echo "[$MODEL] 📁 ${DIR##*/}"
```
## Tips
* Keep your status line concise - it should fit on one line
* Use emojis (if your terminal supports them) and colors to make information scannable
* Use `jq` for JSON parsing in Bash (see examples above)
* Test your script by running it manually with mock JSON input: `echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/test"}}' | ./statusline.sh`
* Consider caching expensive operations (like git status) if needed
## Troubleshooting
* If your status line doesn't appear, check that your script is executable (`chmod +x`)
* Ensure your script outputs to stdout (not stderr)
@@ -0,0 +1,173 @@
# Claude Code Hook Configuration Documentation
**LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits**
## Official Documentation Reference
- **Source**: Claude Code Hooks API Documentation
- **Version**: v2025
- **Last Verified**: 2025-08-31
- **Official URL**: https://docs.anthropic.com/en/docs/claude-code/hooks
## Hook Configuration Structure
### Two Categories of Hooks
Claude Code hooks are divided into two distinct categories with different configuration structures:
#### 1. Tool-Related Hooks
These hooks are triggered in relation to tool usage and require a `matcher` field:
- `PreToolUse`: Executed before a tool is invoked
- `PostToolUse`: Executed after a tool completes
**Configuration Structure:**
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/script.js",
"timeout": 60000
}
]
}
]
}
}
```
#### 2. Non-Tool Hooks
These hooks are triggered by system events and **MUST NOT** have a `matcher` or `pattern` field:
- `PreCompact`: Before conversation compaction
- `SessionStart`: When a new session begins
- `SessionEnd`: When a session ends
- `UserPromptSubmit`: When user submits a prompt
- `Notification`: For system notifications
- `Stop`: When Claude is stopping
- `SubagentStop`: When a subagent is stopping
**Configuration Structure:**
```json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/script.js",
"timeout": 30000
}
]
}
]
}
}
```
## Common Configuration Mistakes
### ❌ INCORRECT: Adding `pattern` field to non-tool hooks
```json
{
"hooks": {
"PreCompact": [
{
"pattern": "*", // WRONG: Non-tool hooks don't use patterns
"hooks": [...]
}
]
}
}
```
### ✅ CORRECT: Non-tool hooks without matcher
```json
{
"hooks": {
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/pre-compact.js",
"timeout": 180000
}
]
}
]
}
}
```
## Hook Field Reference
### Common Fields (All Hooks)
- `type`: Always `"command"` for external scripts
- `command`: Absolute path to the executable script
- `timeout`: Optional timeout in milliseconds (default: 60000)
### Tool Hook Specific
- `matcher`: Regex pattern to match tool names
- Example: `"Edit|MultiEdit|Write"`
- Example: `"mcp__.*__write.*"`
- Example: `"Bash"`
### Environment Variables Available to Hooks
- `$CLAUDE_PROJECT_DIR`: Project root directory
- Standard environment variables from the shell
## Hook Input/Output
### Input (via stdin)
All hooks receive JSON input with common fields:
```json
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"hook_event_name": "string",
// Additional event-specific fields
}
```
### Output Options
Hooks can output:
1. **Plain text** (stdout): Added as context
2. **JSON** (stdout): Structured response for decisions
3. **Exit codes**:
- `0`: Success, continue normally
- `1`: General error
- `2`: Block operation (for PreToolUse)
## Implementation Notes
### File Locations
- User settings: `~/.claude/settings.json`
- Project settings: `./.claude/settings.json`
- Local settings: `./.claude/settings.local.json`
### Settings Precedence (Highest to Lowest)
1. Enterprise managed policies
2. Command line arguments
3. Local project settings
4. Shared project settings
5. User settings
## Cross-References
- Code Implementation: `/Users/alexnewman/Scripts/claude-mem/src/commands/install.ts:263-320`
- Hook Files: `/Users/alexnewman/Scripts/claude-mem/hooks/`
- User Guide: `/Users/alexnewman/Scripts/claude-mem/README-npm.md`
## Version History
- **2025-08-31**: Fixed hook configuration to remove incorrect `pattern` field from non-tool hooks
- **2025-08-31**: Documented official hook structure requirements per Claude Code API
---
*This documentation is maintained by @docs-agent and verified against official Anthropic documentation.*
@@ -0,0 +1,127 @@
# Claude Code Hook Response Format Documentation
## Source: Official Claude Code Docs v2025
## Last Verified: 2025-08-31
## Common Hook Response Fields
All hooks can return these common fields:
```json
{
"continue": true, // Whether Claude should continue (default: true)
"stopReason": "string", // Message shown when continue is false
"suppressOutput": true, // Hide stdout from transcript (default: false)
"systemMessage": "string" // Optional warning message shown to user
}
```
## Hook-Specific Response Formats
### PreCompact Hook
**IMPORTANT**: PreCompact does NOT support `hookSpecificOutput`
```json
{
"continue": true,
"suppressOutput": true
}
```
### SessionStart Hook
SessionStart DOES support `hookSpecificOutput`:
```json
{
"continue": true,
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Context string to add to session"
}
}
```
### PreToolUse Hook
```json
{
"continue": true,
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow" | "deny" | "ask",
"permissionDecisionReason": "Reason for decision"
}
}
```
### PostToolUse Hook
```json
{
"decision": "block", // Optional - blocks further processing
"reason": "Explanation",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Claude"
}
}
```
### UserPromptSubmit Hook
```json
{
"decision": "block", // Optional - blocks the prompt
"reason": "Security policy violation",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Additional context for the prompt"
}
}
```
## Exit Codes
- `0`: Success - hook executed successfully
- `1`: Error - shown to user with stdout
- `2`: Error - shown to Claude with stderr
## Common Mistakes to Avoid
### \u274c INCORRECT: Using wrong field names
```javascript
// WRONG
{
"decision": "block", // \u274c Wrong field
"reason": "Error message" // \u274c Wrong field
}
```
### \u2705 CORRECT: Using official field names
```javascript
// RIGHT
{
"continue": false,
"stopReason": "Error message"
}
```
### \u274c INCORRECT: Adding hookSpecificOutput to PreCompact
```javascript
// WRONG - PreCompact doesn't support this
{
"hookSpecificOutput": {
"hookEventName": "PreCompact",
"status": "success"
}
}
```
### \u2705 CORRECT: Simple response for PreCompact
```javascript
// RIGHT
{
"continue": true,
"suppressOutput": true
}
```
## References
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
- Hook Examples: https://docs.anthropic.com/en/docs/claude-code/hooks-guide
+175
View File
@@ -0,0 +1,175 @@
# Claude Code Hooks Configuration Documentation
## Source: Official Claude Code Docs v2025
## Last Verified: 2025-08-31
## Hook Configuration Structure
### For Tool-Based Hooks (PreToolUse, PostToolUse)
These hooks use the `matcher` field to match tool patterns:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "ToolPattern", // Required for tool hooks
"hooks": [
{
"type": "command",
"command": "your-command-here",
"timeout": 60000 // Optional, in milliseconds
}
]
}
]
}
}
```
### For Non-Tool Hooks (PreCompact, SessionStart, etc.)
These hooks DO NOT use matcher/pattern fields:
```json
{
"hooks": {
"PreCompact": [
{
// NO matcher or pattern field!
"hooks": [
{
"type": "command",
"command": "/path/to/script.js",
"timeout": 180000
}
]
}
]
}
}
```
## Available Hook Events
### Tool-Related Hooks (use matcher)
- **PreToolUse**: Before tool execution
- **PostToolUse**: After tool execution
### System Event Hooks (no matcher)
- **PreCompact**: Before conversation compaction
- **SessionStart**: When session begins
- **SessionEnd**: When session ends (not in official docs)
- **UserPromptSubmit**: When user submits prompt
- **Notification**: When Claude needs user input
- **Stop**: When stop is requested
- **SubagentStop**: When subagent stop is requested
## Hook Payload Structure
### Common Fields (all hooks)
```json
{
"session_id": "string",
"transcript_path": "string",
"hook_event_name": "string",
"cwd": "string" // Current working directory
}
```
### PreCompact Specific
```json
{
"hook_event_name": "PreCompact",
"trigger": "manual" | "auto",
"custom_instructions": "string"
}
```
### SessionStart Specific
```json
{
"hook_event_name": "SessionStart",
"source": "startup" | "compact" | "vscode" | "web"
}
```
### PreToolUse/PostToolUse Specific
```json
{
"tool_name": "string",
"tool_input": { /* tool specific */ },
"tool_response": { /* PostToolUse only */ }
}
```
## Common Configuration Mistakes
### \u274c INCORRECT: Using 'pattern' for non-tool hooks
```json
{
"hooks": {
"PreCompact": [{
"pattern": "*", // \u274c WRONG - non-tool hooks don't use this
"hooks": [...]
}]
}
}
```
### \u2705 CORRECT: No matcher for non-tool hooks
```json
{
"hooks": {
"PreCompact": [{
// No pattern or matcher field
"hooks": [...]
}]
}
}
```
### \u274c INCORRECT: Wrong matcher field name
```json
{
"hooks": {
"PreToolUse": [{
"pattern": "Bash", // \u274c WRONG field name
"hooks": [...]
}]
}
}
```
### \u2705 CORRECT: Using 'matcher' for tool hooks
```json
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash", // \u2705 Correct field name
"hooks": [...]
}]
}
}
```
## Matcher Patterns for Tool Hooks
- **Exact match**: `"Bash"` - matches only Bash tool
- **Multiple tools**: `"Edit|MultiEdit|Write"` - matches any of these
- **MCP tools**: `"mcp__memory__.*"` - matches all memory server tools
- **All tools**: `"*"` - matches everything
## Environment Variables
Hooks have access to:
- `$CLAUDE_PROJECT_DIR` - Project root directory
## Settings File Locations
1. **User settings**: `~/.claude/settings.json`
2. **Project settings**: `./.claude/settings.json`
3. **Local settings**: `./.claude/settings.local.json`
4. **Managed settings**: `/Library/Application Support/ClaudeCode/managed-settings.json`
## References
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
- Hook Guide: https://docs.anthropic.com/en/docs/claude-code/hooks-guide
@@ -0,0 +1,133 @@
# MCP Configuration Documentation
## Source: Official Claude Code Docs v2025
## Last Verified: 2025-08-31
## MCP Configuration File Locations
### User Scope
- **File**: `~/.claude.json`
- **Purpose**: User-wide MCP servers available across all projects
- **Persistence**: Persists across projects
- **Example Path**: `/Users/username/.claude.json`
### Project Scope
- **File**: `./.mcp.json`
- **Purpose**: Project-specific servers for team collaboration
- **Persistence**: Checked into version control
- **Example Path**: `/path/to/project/.mcp.json`
### Local Scope
- **Status**: Not officially documented
- **Implementation**: Currently uses `~/.claude.json` (may need revision)
## Configuration Structure
```json
{
"mcpServers": {
"server-name": {
"command": "command-to-run",
"args": ["arg1", "arg2"],
"env": {
"ENV_VAR": "value"
}
}
}
}
```
## Example Configurations
### Memory Server (stdio)
```json
{
"mcpServers": {
"claude-mem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
}
}
}
```
### HTTP Server
```json
{
"mcpServers": {
"api-server": {
"type": "sse",
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}
```
## Environment Variable Expansion
MCP configs support environment variable expansion:
- `${VAR}` - Direct expansion
- `${VAR:-default}` - With fallback value
Applicable fields:
- `command`
- `args`
- `env`
- `url`
- `headers`
## CLI Commands
```bash
# Add a server
claude mcp add <name> <command> [args...]
# Add with scope
claude mcp add <name> --scope project /path/to/server
claude mcp add <name> --scope user /path/to/server
# List servers
claude mcp list
# Get server details
claude mcp get <name>
# Remove server
claude mcp remove <name>
# Check status (within Claude Code)
/mcp
```
## Tool Naming Convention
MCP tools follow the pattern: `mcp__<serverName>__<toolName>`
Example:
- Server: `claude-mem`
- Tool: `create_entities`
- Full name: `mcp__claude_mem__create_entities`
## Security Considerations
1. **Tool Permissions**: Must explicitly allow MCP tools via `--allowedTools`
2. **Server Trust**: Only use MCP servers from trusted sources
3. **Credential Management**: Use environment variables for sensitive data
4. **Audit Trail**: MCP operations can be monitored via hooks
## Common Issues
### Issue: MCP server not connecting
**Solution**: Check that the command and args are correct, and npx is in PATH
### Issue: Tools not available
**Solution**: Ensure server is in allowed list and properly configured
### Issue: Configuration not loading
**Solution**: Verify JSON syntax and file location
## References
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/mcp
- MCP Protocol: https://modelcontextprotocol.io/
@@ -0,0 +1,82 @@
# SessionStart Hook Documentation
## Official Documentation Reference
- **Source**: https://docs.anthropic.com/en/docs/claude-code/hooks#sessionstart
- **Last Verified**: 2025-08-31
- **Version**: Claude Code v2025
## Hook Payload Structure
The SessionStart hook receives the following JSON payload via stdin:
```json
{
"session_id": "string",
"transcript_path": "string",
"hook_event_name": "SessionStart",
"source": "startup" | "compact" | "vscode" | "web"
}
```
### Field Descriptions
- **session_id**: Unique identifier for the Claude Code session
- **transcript_path**: Path to the conversation transcript JSONL file
- **hook_event_name**: Always "SessionStart" for this hook
- **source**: Indicates how the session was initiated:
- `"startup"`: New session started normally (should load context)
- `"compact"`: Session started after compaction (may skip context)
- `"vscode"`: Session initiated from VS Code extension
- `"web"`: Session initiated from web interface
## Response Format
The hook should output JSON in the following format to add context:
```json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "string"
}
}
```
### Response Fields
- **hookSpecificOutput**: Container for hook-specific output
- **hookEventName**: Must be "SessionStart"
- **additionalContext**: String content to add to the session context
## Implementation Notes
### Context Loading Strategy
The hook should determine whether to load context based on the `source` field:
1. **For "startup" source**: Load full context from memory
2. **For "compact" source**: Skip or load minimal context (session continuing after compaction)
3. **For "vscode"/"web" sources**: Load context as appropriate
### Error Handling
- If context loading fails, exit silently (exit code 0)
- Do not break the session start with errors
- Log errors to separate log file if needed
## Common Mistakes
### Incorrect Field Check (FIXED)
**Wrong**: Checking `payload.reason === 'continue'`
**Correct**: Checking `payload.source === 'compact'`
The payload does not have a `reason` field. The `source` field indicates the session initiation context.
## Code Location
- **File**: `/Users/alexnewman/Scripts/claude-mem/hooks/session-start.js`
- **Line**: 53-66 (field check and documentation)
## Cross-References
- General Hooks Documentation: [docs/claude-code/hooks.md](./hooks.md)
- Hook Response Formats: [docs/claude-code/hook-responses.md](./hook-responses.md)
- MCP Configuration: [docs/claude-code/mcp-configuration.md](./mcp-configuration.md)