8.6 KiB
Hook System Conventions
Convention-based patterns for zero-config hook customization.
Overview
Conventions allow project-specific hook behavior without editing gates.json. Place files following naming patterns and they auto-execute at the right time.
Convention Types
1. Context Injection
Purpose: Auto-inject content into conversation at hook events.
Patterns:
Basic Pattern: .claude/context/{name}-{stage}.md
- Commands:
.claude/context/commit-start.md - Skills:
.claude/context/test-driven-development-start.md - Agents:
.claude/context/commit-agent-end.md
Agent-Command Scoping: .claude/context/{agent}-{command}-{stage}.md
- Specific agent + command:
.claude/context/commit-agent-commit-start.md - Agent with different command:
.claude/context/rust-agent-execute-end.md - Plan review agent:
.claude/context/plan-review-agent-verify-start.md
Supported hooks:
SessionStart- At beginning of Claude Code sessionSessionEnd- At end of Claude Code sessionSlashCommandStart- Before command executesSlashCommandEnd- After command completesSkillStart- When skill loadsSkillEnd- When skill completesSubagentStop- After agent completes (supports agent-command scoping)UserPromptSubmit- Before user prompt is processedPreToolUse- Before a tool is usedPostToolUse- After a tool is usedStop- When agent stopsNotification- When notification is received
All Claude Code hook types are supported. Plugin provides default context for SessionStart via ${CLAUDE_PLUGIN_ROOT}/context/session-start.md.
Examples:
# Generic command context - any invocation
.claude/context/commit-start.md
# Generic agent context - any command using this agent
.claude/context/commit-agent-end.md
# Agent-command specific - commit-agent invoked by /commit
.claude/context/commit-agent-commit-start.md
# Agent-command specific - rust-agent invoked by /execute
.claude/context/rust-agent-execute-end.md
# Planning template for /plan command
.claude/context/plan-start.md
# TDD standards when skill loads
.claude/context/test-driven-development-start.md
2. Directory Organization
Small projects (<5 files):
.claude/context/{name}-{stage}.md
Medium projects (5-20 files):
.claude/context/slash-command/{name}-{stage}.md
.claude/context/skill/{name}-{stage}.md
Large projects (>20 files):
.claude/context/slash-command/{name}/{stage}.md
.claude/context/skill/{name}/{stage}.md
All structures supported - use what fits your project size.
Discovery Order
Dispatcher searches paths in priority order. Project-level context takes precedence over plugin-level context.
For SubagentStop (agent completion):
Project paths (checked first):
.claude/context/{agent}-{command}-end.md(agent + command/skill).claude/context/{agent}-end.md(agent only)
Plugin paths (fallback):
3. ${CLAUDE_PLUGIN_ROOT}/context/{agent}-{command}-end.md
4. ${CLAUDE_PLUGIN_ROOT}/context/{agent}-end.md
Standard discovery (backward compat): 5. Command/skill-specific paths
For Commands and Skills:
Project paths (checked first):
.claude/context/{name}-{stage}.md.claude/context/slash-command/{name}-{stage}.md.claude/context/slash-command/{name}/{stage}.md.claude/context/skill/{name}-{stage}.md.claude/context/skill/{name}/{stage}.md
Plugin paths (fallback):
6. ${CLAUDE_PLUGIN_ROOT}/context/{name}-{stage}.md
7. ${CLAUDE_PLUGIN_ROOT}/context/slash-command/{name}-{stage}.md
8. ${CLAUDE_PLUGIN_ROOT}/context/slash-command/{name}/{stage}.md
9. ${CLAUDE_PLUGIN_ROOT}/context/skill/{name}-{stage}.md
10. ${CLAUDE_PLUGIN_ROOT}/context/skill/{name}/{stage}.md
First match wins.
Priority Example (SubagentStop):
Agent: rust-agent
Active command: /execute
Search order:
1. rust-agent-execute-end.md (most specific)
2. rust-agent-end.md (agent-specific)
3. execute-end.md (command-specific, backward compat)
Naming Rules
Command Names
- Remove leading slash and namespace:
/turboshovel:code-review→code-review - Use exact command name:
/turboshovel:plan→plan - Lowercase with hyphens
Skill Names
- Remove namespace prefix:
turboshovel:executing-plans→executing-plans - Use exact skill name (may include hyphens)
- Example:
test-driven-development - Example:
conducting-code-review
Agent Names
- Remove namespace prefix:
turboshovel:rust-agent→rust-agent - Use exact agent name (may include hyphens)
- Example:
commit-agent - Example:
code-review-agent - Example:
review-collation-agent
Stage Names
start- Before executionend- After completion- Lowercase only
Content Format
Context files are markdown with any structure:
## Project Requirements
List your requirements here.
### Security
- Requirement 1
- Requirement 2
### Performance
- Benchmark targets
- Optimization goals
Content appears as additionalContext in conversation.
Execution Model
Injection Timing
Before explicit gates:
1. Convention file exists? → Auto-inject
2. Run explicit gates (from gates.json)
3. Continue or block based on results
Example flow for /code-review:
1. SlashCommandStart fires
2. Check for .claude/context/code-review-start.md
3. If exists → inject content
4. Run configured gates (e.g., verify-structure)
5. Continue if all pass
Combining Conventions and Gates
Zero-config approach:
# Just create file - auto-injects!
echo "## Requirements..." > .claude/context/code-review-start.md
Mixed approach:
# Convention file for injection
.claude/context/code-review-start.md
# Plus explicit gates for verification
{
"hooks": {
"SlashCommandEnd": {
"enabled_commands": ["/code-review"],
"gates": ["verify-structure", "test"]
}
}
}
Execution: Inject context → Run verify-structure → Run test
Control and Disabling
Disable Convention
Method 1: Rename file
mv .claude/context/code-review-start.md \
.claude/context/code-review-start.md.disabled
Method 2: Move to non-discovery path
mkdir -p .claude/disabled
mv .claude/context/code-review-start.md .claude/disabled/
Method 3: Delete file
rm .claude/context/code-review-start.md
No config changes needed - control via file presence.
Enable Convention
Move/rename file back to discovery path:
mv .claude/context/code-review-start.md.disabled \
.claude/context/code-review-start.md
Common Patterns
Pattern: Review Requirements
File: .claude/context/code-review-start.md
Triggered by: /turboshovel:code-review command
Content example:
## Security Requirements
- Authentication required
- Input validation
- No secrets in logs
## Performance Requirements
- No N+1 queries
- Response time < 200ms
Pattern: Planning Template
File: .claude/context/plan-start.md
Triggered by: /turboshovel:plan command
Content example:
## Plan Structure
Must include:
1. Architecture impact
2. Testing strategy
3. Deployment plan
4. Success criteria
Pattern: Skill Standards
File: .claude/context/test-driven-development-start.md
Triggered by: TDD skill loading
Content example:
## Project TDD Standards
Framework: Vitest
Location: src/**/__tests__/*.test.ts
Coverage: 80% minimum
Migration from Custom Scripts
Before (custom script):
# .claude/gates/inject-requirements.sh
#!/bin/bash
cat .claude/requirements.md | jq -Rs '{additionalContext: .}'
After (convention):
# Just rename/move the file!
mv .claude/requirements.md .claude/context/code-review-start.md
Zero scripting needed.
Best Practices
- File Organization: Start flat, grow hierarchically as needed
- Naming: Use exact command/skill names (lowercase-only stage names)
- Content: Keep focused - one concern per file
- Discovery: Let multiple paths support project evolution
- Control: Rename/move files rather than editing gates.json
Debugging
Check if file discovered:
export TURBOSHOVEL_HOOK_DEBUG=true
tail -f $TMPDIR/turboshovel-hooks-$(date +%Y%m%d).log
Look for: "dispatcher: Context file: /path/to/file.md"
Common issues:
- Wrong file name (check exact command/skill name)
- Wrong stage name (must be
startorend, lowercase) - File not in discovery path (check supported structures)
- Permissions (file must be readable)
Examples Directory
See plugin/hooks/examples/context/ for working examples:
- Code review requirements
- Planning templates
- TDD standards
Copy and customize for your project.