CC-301m · Module 3
Hook-Based Instruction Injection
4 min read
Hooks execute instructions at specific moments in the session lifecycle. Used well, they inject the right constraints at the right time — before a tool runs, after a file is edited, at session start. Used poorly, they add noise that the agent processes and ignores. The difference is specificity: a hook that says something actionable at the moment it fires is useful. A hook that outputs generic advice is overhead.
- Match the hook to the moment Pre-tool hooks fire before a tool executes. Use them to inject constraints relevant to that specific tool — not general advice. A pre-bash hook that reminds the agent to be careful with shell commands is noise. A pre-bash hook that says "check: does this command modify the production database?" fires at the right moment with a specific, evaluable question.
- Make hook output evaluable Hook output should contain either a condition to check ('Is this change inside the authorized scope?') or a fact to use ('Today is [date], branch is [branch], last deploy was [datetime]'). Advice hooks — 'remember to write clean code' — produce nothing the agent can act on.
- Use session-start hooks for context injection SessionStart hooks are the mechanism for injecting dynamic context that does not belong in CLAUDE.md: current date, current git status, environment state. Keep them focused on facts, not instructions — CLAUDE.md is the instruction layer. Hooks are the context layer.
- Test hooks in isolation Before deploying a hook, test what it outputs for a representative set of tool calls. Hooks that fire unexpectedly often or output unhelpful content degrade the session rather than improving it. The question for every hook: does it change agent behavior in the moment it fires? If not, remove it.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "echo 'CONSTRAINT: Never run git push --force. Never drop tables. Check: is this command reversible?'"
}]
}
],
"SessionStart": [
{
"hooks": [{
"type": "command",
"command": "echo "Session context: $(date '+%Y-%m-%d'), branch: $(git branch --show-current), uncommitted changes: $(git status --porcelain | wc -l | tr -d ' ')""
}]
}
]
}
}