Claude Code Hooks
Turn Claude Code into a self-validating agent. When Claude edits a UI component, Buoy automatically checks for design drift and feeds corrections backβcreating a closed loop where the AI catches and fixes its own mistakes.
How It Works
Claude Code supports hooksβshell
commands that run at specific points in the AI's workflow. Buoy uses the PostToolUse
hook to validate files after Claude writes them:
- Claude generates or edits a component file
- The hook runs
buoy drift checkon the modified file - If drift is detected, feedback returns to Claude
- Claude self-corrects without you asking
Quick Setup
buoy dock hooks --claude This creates two files:
.claude/hooks/buoy-validate.jsβ The validation script.claude/settings.local.jsonβ Hook configuration
What Gets Checked
The hook validates these file types:
.tsx,.jsxβ React components.vueβ Vue components.svelteβ Svelte components.component.ts,.component.htmlβ Angular components
It skips test files, stories, config files, and type definitions.
Example Feedback
When Claude writes a component with hardcoded values, it sees:
β οΈ Design drift detected in Button.tsx:
β’ hardcoded-value: Component "Button" has 3 hardcoded colors: #3b82f6, #ffffff, #1e40af
β’ hardcoded-value: Component "Button" has 2 hardcoded size values: 8px, 16px
Run `buoy show drift` for full details. Claude then fixes the issues automatically in its next edit.
Manual Setup
If you prefer to set up manually, create .claude/settings.local.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/buoy-validate.js\""
}
]
},
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/buoy-validate.js\""
}
]
}
]
}
} Then copy the validation script from the Buoy repository.
Configuration
Adjusting Severity
By default, all drift types trigger feedback. To only report critical issues, modify the hook script's buoy drift check call:
npx ahoybuoy drift check --format json --fail-on critical Quiet Mode
To reduce noise, use the --quiet flag:
npx ahoybuoy drift check --format json --quiet Combining with Other Hooks
The Buoy hook works alongside other Claude Code hooks. For example, you might have:
SessionStartβ Load design system contextPostToolUseβ Buoy validation (this hook)PreToolUseβ Custom approval workflows
Troubleshooting
Hook Not Running
Verify the hook is configured:
cat .claude/settings.local.json | jq '.hooks' No Feedback Appearing
Test the hook manually:
echo '{"tool_name":"Write","tool_input":{"file_path":"src/Button.tsx"},"cwd":"'$(pwd)'"}' | node .claude/hooks/buoy-validate.js Permission Errors
Ensure the script is executable:
chmod +x .claude/hooks/buoy-validate.js How the Script Works
The validation script:
- Receives JSON from Claude Code via stdin with the modified file path
- Checks if it's a UI component file (by extension)
- Runs
buoy drift check --format json - Filters results to only the modified file
- Returns structured feedback via
hookSpecificOutput.additionalContext
The script always exits with code 0βit provides feedback without blocking Claude's workflow.
Related
- buoy drift check β The command that powers the hook
- buoy dock β Project setup including hooks
- AI Guardrails β Broader AI integration strategy
- GitHub App β CI/CD integration