mirror of
https://github.com/imjasonh/cnotes
synced 2026-07-08 09:05:17 +00:00
Add comprehensive documentation for the git notes functionality: - Example usage and real-world scenarios - Commands for viewing conversation context attached to commits - Configuration options via .claude/notes.json - Privacy controls and sensitive data filtering - Team collaboration workflows for sharing git notes - Complete JSON example showing structured conversation data Users can now easily understand how to view and configure the automatic conversation context attachment to their git commits. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
292 lines
No EOL
8 KiB
Markdown
292 lines
No EOL
8 KiB
Markdown
# Claude Code Hooks
|
|
|
|
A Go binary that handles Claude Code hooks for validating and modifying tool usage. This tool makes it easy to write custom hooks as simple Go functions.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
go build -o hooks
|
|
./hooks install
|
|
```
|
|
|
|
This will configure your `~/.claude/settings.json` to use this binary for all hook events.
|
|
|
|
## Usage
|
|
|
|
### Writing Custom Hooks
|
|
|
|
Hooks are simple Go functions that follow this signature:
|
|
|
|
```go
|
|
func MyHook(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error) {
|
|
// Your logic here
|
|
return hooks.HookOutput{Decision: "continue"}, nil
|
|
}
|
|
```
|
|
|
|
Register your hook in an init function:
|
|
|
|
```go
|
|
func init() {
|
|
// Register for specific tools
|
|
hooks.RegisterHook(hooks.EventPreToolUse, "Bash", ValidateBashCommand)
|
|
|
|
// Use regex patterns
|
|
hooks.RegisterHook(hooks.EventPreToolUse, "Write|Edit", PreventSensitiveEdits)
|
|
|
|
// Match all tools
|
|
hooks.RegisterHook(hooks.EventPostToolUse, "*", LogEverything)
|
|
}
|
|
```
|
|
|
|
### Example: Block Dangerous Commands
|
|
|
|
```go
|
|
func BlockRmRf(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error) {
|
|
bashInput, err := input.GetBashInput()
|
|
if err != nil {
|
|
return hooks.HookOutput{Decision: "approve"}, nil
|
|
}
|
|
|
|
if strings.Contains(bashInput.Command, "rm -rf /") {
|
|
return hooks.HookOutput{
|
|
Decision: "block",
|
|
Reason: "Cannot execute rm -rf on root directory",
|
|
}, nil
|
|
}
|
|
return hooks.HookOutput{Decision: "approve"}, nil
|
|
}
|
|
```
|
|
|
|
### Example: Add Context to Prompts
|
|
|
|
```go
|
|
func AddGitInfo(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error) {
|
|
branch := getCurrentGitBranch()
|
|
return hooks.HookOutput{
|
|
Decision: "continue",
|
|
AdditionalContext: fmt.Sprintf("Current git branch: %s", branch),
|
|
}, nil
|
|
}
|
|
```
|
|
|
|
### Example: Modify Tool Parameters
|
|
|
|
```go
|
|
func ForceNonInteractiveSudo(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error) {
|
|
bashInput, err := input.GetBashInput()
|
|
if err != nil {
|
|
return hooks.HookOutput{Decision: "approve"}, nil
|
|
}
|
|
|
|
if strings.Contains(bashInput.Command, "sudo") && !strings.Contains(bashInput.Command, "sudo -n") {
|
|
return hooks.HookOutput{
|
|
Decision: "approve",
|
|
ModifiedParameters: map[string]interface{}{
|
|
"command": strings.ReplaceAll(bashInput.Command, "sudo", "sudo -n"),
|
|
},
|
|
}, nil
|
|
}
|
|
return hooks.HookOutput{Decision: "approve"}, nil
|
|
}
|
|
```
|
|
|
|
## Built-in Hooks
|
|
|
|
This package includes comprehensive hook implementations for all Claude Code events:
|
|
|
|
### Pre Tool Use
|
|
- **Bash Command Validator**: Blocks dangerous commands using regex patterns
|
|
- **Sensitive File Protection**: Prevents editing `.env`, `.aws/credentials`, etc.
|
|
|
|
### Post Tool Use
|
|
- **Tool Usage Logger**: Logs all tool executions with structured logging
|
|
- **Go Imports**: Automatically runs `goimports -w` on modified Go files
|
|
|
|
### User Prompt Submit
|
|
- **Project Context**: Adds git branch and project type information
|
|
|
|
### Notification
|
|
- **System Notifications**: Logs notification events for debugging and monitoring
|
|
|
|
### Stop
|
|
- **Session Completion**: Logs when main Claude agent finishes responding
|
|
|
|
### SubagentStop
|
|
- **Subagent Completion**: Logs when Task tool subagents finish responding
|
|
|
|
### PreCompact
|
|
- **Context Compaction**: Handles before context window compaction (manual/auto)
|
|
|
|
## Git Notes Integration
|
|
|
|
This hooks system automatically attaches Claude conversation context to git commits using [git notes](https://git-scm.com/docs/git-notes). When you run `git commit` commands, the system captures relevant conversation context and stores it alongside your commits.
|
|
|
|
### What Gets Stored
|
|
|
|
Each git note contains structured JSON data with:
|
|
- **Session ID**: Unique identifier for the Claude session
|
|
- **Timestamp**: When the commit was made
|
|
- **Conversation Excerpt**: Recent user prompts and tool interactions
|
|
- **Tools Used**: List of tools used during the conversation
|
|
- **Commit Context**: Details about the git command and output
|
|
- **Claude Version**: Which version of Claude created the commit
|
|
|
|
### Example Usage
|
|
|
|
Let's say you're working on a project and ask Claude to implement a feature:
|
|
|
|
```bash
|
|
# You: "Add user authentication to the login form"
|
|
# Claude uses various tools (Edit, Write, Bash) to implement the feature
|
|
# Then creates a commit:
|
|
|
|
git commit -m "Add user authentication with password validation
|
|
|
|
- Implement bcrypt password hashing
|
|
- Add login form validation
|
|
- Create user session management
|
|
- Add error handling for failed logins"
|
|
```
|
|
|
|
The hook automatically captures the conversation context and attaches it to the commit.
|
|
|
|
### Viewing Conversation Context
|
|
|
|
To view the conversation context attached to any commit:
|
|
|
|
```bash
|
|
# View notes for the latest commit
|
|
git notes --ref=claude-conversations show HEAD
|
|
|
|
# View notes for a specific commit
|
|
git notes --ref=claude-conversations show abc1234
|
|
|
|
# View notes in git log (one-liner)
|
|
git log --show-notes=claude-conversations --oneline
|
|
|
|
# View detailed notes in git log
|
|
git log --show-notes=claude-conversations -1
|
|
```
|
|
|
|
### Example Output
|
|
|
|
```json
|
|
{
|
|
"session_id": "claude_session_20250121_143022",
|
|
"timestamp": "2025-01-21T14:30:45Z",
|
|
"conversation_excerpt": "Recent user prompts:\n- Add user authentication to the login form\n- Make sure to use bcrypt for password hashing\n\nTool interactions:\n- Edit: components/LoginForm.jsx\n- Write: utils/auth.js\n- Bash: npm install bcrypt",
|
|
"tools_used": ["Edit", "Write", "Bash"],
|
|
"commit_context": "Git command: git commit -m 'Add user authentication with password validation'\nResult: [main abc1234] Add user authentication with password validation",
|
|
"claude_version": "claude-sonnet-4-20250514"
|
|
}
|
|
```
|
|
|
|
### Configuration
|
|
|
|
Customize the git notes behavior by creating `.claude/notes.json`:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"max_excerpt_length": 5000,
|
|
"max_prompts": 2,
|
|
"include_tool_output": false,
|
|
"notes_ref": "claude-conversations",
|
|
"exclude_patterns": ["password", "token", "key", "secret"]
|
|
}
|
|
```
|
|
|
|
### Privacy Controls
|
|
|
|
The system includes built-in privacy protections:
|
|
- Automatically filters sensitive patterns (passwords, tokens, keys)
|
|
- Limits excerpt length to prevent excessive data storage
|
|
- Only includes conversation context from the current session
|
|
- Configurable exclusion patterns
|
|
- Option to disable entirely (`"enabled": false`)
|
|
|
|
### Sharing Git Notes
|
|
|
|
Git notes are stored locally by default. To share them with your team:
|
|
|
|
```bash
|
|
# Push notes to remote repository
|
|
git push origin refs/notes/claude-conversations
|
|
|
|
# Pull notes from remote repository
|
|
git fetch origin refs/notes/claude-conversations:refs/notes/claude-conversations
|
|
|
|
# Configure automatic notes fetching
|
|
git config remote.origin.fetch '+refs/notes/*:refs/notes/*'
|
|
```
|
|
|
|
## Testing Hooks
|
|
|
|
Test individual hooks by piping JSON:
|
|
|
|
```bash
|
|
echo '{
|
|
"event": "pre_tool_use",
|
|
"tool": "Bash",
|
|
"tool_use_request": {
|
|
"tool": "Bash",
|
|
"parameters": {
|
|
"command": "rm -rf /"
|
|
}
|
|
}
|
|
}' | ./hooks run
|
|
```
|
|
|
|
Enable debug logging:
|
|
|
|
```bash
|
|
./hooks run --debug
|
|
```
|
|
|
|
## Hook Events
|
|
|
|
- `pre_tool_use`: Before any tool execution
|
|
- `post_tool_use`: After successful tool execution
|
|
- `user_prompt_submit`: Before processing user prompts
|
|
- `stop`: When main agent finishes
|
|
- `subagent_stop`: When subagent finishes
|
|
- `notification`: For permission requests
|
|
- `pre_compact`: Before context compaction
|
|
|
|
## Configuration
|
|
|
|
Hooks are configured in `~/.claude/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"hooks": [
|
|
{
|
|
"events": ["pre_tool_use", "post_tool_use"],
|
|
"matchers": [".*"],
|
|
"cmds": ["/path/to/hooks run"]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Security Warning
|
|
|
|
⚠️ **USE AT YOUR OWN RISK**: Hooks execute automatically when Claude Code runs tools. Ensure your hooks are thoroughly tested and secure.
|
|
|
|
## Development
|
|
|
|
To add new hooks:
|
|
|
|
1. Create a new file in `internal/handlers/`
|
|
2. Write your hook function
|
|
3. Register it in an `init()` function
|
|
4. Rebuild and reinstall: `go build && ./hooks install`
|
|
|
|
## Uninstalling
|
|
|
|
```bash
|
|
./hooks install --uninstall
|
|
```
|
|
|
|
This removes all hook configurations from your Claude settings. |