1
0
Fork 0
mirror of https://github.com/imjasonh/cnotes synced 2026-07-08 09:05:17 +00:00
cnotes/CLAUDE.md
Jason Hall 45ef980233
Scaffold all 7 hook events and eliminate type casting
- Add missing hook handlers: Stop, SubagentStop, PreCompact
- Replace all string type casting with proper JSON unmarshaling
- Change ToolUseRequest.Parameters from map[string]interface{} to json.RawMessage
- Update helper methods to use json.Unmarshal directly to typed structs
- Replace speech notifications with simple logging notifications
- Update documentation to reflect all hook events and remove speech references
- Add comprehensive CLAUDE.md with architecture overview and development guidance

All hooks now use type-safe JSON handling without .(string) assertions.
Complete coverage of Claude Code events: PreToolUse, PostToolUse,
UserPromptSubmit, Notification, Stop, SubagentStop, PreCompact.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 12:01:55 -04:00

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Build and Run Commands

# Build the binary
go build -o hooks

# Install hooks to Claude settings (project-level by default)
./hooks install

# Install to different scopes
./hooks install --global    # ~/.claude/settings.json
./hooks install --local     # ./.claude/settings.local.json

# Uninstall hooks
./hooks install --uninstall

# Test hook execution manually (for debugging)
echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":"{\"command\":\"ls\"}"}' | ./hooks run

# Run with debug logging
./hooks run --debug

Architecture Overview

This is a Claude Code hooks system that intercepts and processes all tool usage events. The architecture follows a registry pattern where individual hook handlers register themselves for specific events and tools.

Core Components

internal/hooks/ - Core hook engine

  • types.go - Defines all hook input/output types and helper methods. Uses json.RawMessage for parameters to avoid type casting
  • registry.go - Central registry for mapping events+tools to handler functions
  • runner.go - Main execution engine that processes hook chains and handles JSON I/O

internal/handlers/ - Hook implementations

  • Each file implements handlers for specific events (pretooluse.go, posttooluse.go, etc.)
  • Handlers auto-register in init() functions when package is imported
  • All 7 Claude Code events are implemented: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop, SubagentStop, PreCompact

internal/config/ - Claude settings management

  • settings.go - Handles reading/writing Claude's settings.json files with support for global, local, and project-level configurations

cmd/ - CLI interface using Cobra

  • run.go - Handles hook execution (called by Claude Code)
  • install.go - Manages hook installation/uninstallation

Type Safety and JSON Handling

The codebase avoids string type casting entirely by:

  1. Using json.RawMessage for all parameter storage
  2. Providing typed structs (BashToolInput, FileToolInput) for tool-specific data
  3. Using input.GetBashInput(), input.GetFileInput() helper methods that unmarshal JSON directly to typed structs
  4. Never using .(string) type assertions anywhere in the codebase

Hook Registration Pattern

func init() {
    hooks.RegisterHook(hooks.EventPreToolUse, "Bash", ValidateBashCommand)
    hooks.RegisterHook(hooks.EventPreToolUse, "Write|Edit|MultiEdit", PreventSensitiveFileEdits) 
}

Matchers support:

  • Exact tool names: "Bash"
  • Regex patterns: "Write|Edit|MultiEdit"
  • Wildcard: "*" for all tools

Hook Function Signature

All hook functions follow this signature:

func HookName(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error)

Hook outputs can:

  • Block execution: Decision: "block"
  • Allow with modifications: Decision: "approve" + ModifiedParameters
  • Add context to responses: AdditionalContext
  • Modify user prompts: ModifiedUserPrompt

Settings File Structure

The system uses Claude's native hook configuration format with proper event name mapping:

{
  "hooks": {
    "PreToolUse": [{"matcher": ".*", "hooks": [{"type": "command", "command": "/path/to/hooks run"}]}],
    "PostToolUse": [{"matcher": ".*", "hooks": [{"type": "command", "command": "/path/to/hooks run"}]}]
  }
}

Key Design Principles

  • No Type Casting: All JSON handling uses proper unmarshaling to typed structs
  • Auto-Registration: Hook handlers register themselves via init() functions
  • Comprehensive Coverage: All 7 Claude Code events are implemented with placeholder functionality
  • Project-First: Defaults to project-level .claude/settings.json installation
  • Extensible: Easy to add new hook handlers by creating new files in internal/handlers/

When adding new hooks, create a new file in internal/handlers/, implement the hook function, and register it in an init() function. The handler will be automatically loaded when the package is imported.