Five Claude Code hooks that keep your regression green
An MCP server gives the agent tools it can choose to call. Hooks are different: they fire on real events in the agent loop whether the agent thinks to or not. That makes them the right place for the deterministic, no-AI checks that keep a coding agent honest — orient it at the start, and refuse to let it call a task "done" while a spec is red.
Hover ships a hover-hook bin (it comes with @hover-dev/mcp). Run hover-hook install in your repo and it wires the first hooks below into .claude/settings.json. The rest are patterns you can add in a few lines. Here are the five that pay off, each mapped to the Claude Code event it rides.
1. SessionStart → inject Cloud state + the active environment
The cheapest win. When a session opens, the hook calls Hover's cloud_context / heal-queue reads and injects a short block through hookSpecificOutput.additionalContext:
Hover: active environment staging (https://staging.acme.dev). Cloud connected; project acme/store. 3 specs drifted in CI: checkout, login, search — heal with
/mcp__hover__heal <slug>.
The agent starts knowing the whole picture — which environment a run targets, what's already red — without you typing a word. It's the proactive form of the cloud_context tool. hover-hook install wires this.
2. Stop → a deterministic "must be green before you finish" gate
The killer one. When the agent says it's done, the Stop hook runs — and it can refuse. Run the affected crystallized specs; if one is red, return:
{ "decision": "block", "reason": "checkout.spec.ts failed — fix it before finishing." }
(or exit 2). Now "done" means the suite deterministically passes, not that the agent felt finished. Claude Code caps consecutive blocks and sets stop_hook_active, so you can't loop forever.
Running once per turn on Stop beats running on every Edit in PostToolUse — you check when it matters instead of firing a browser suite on every keystroke. hover-hook install ships a Stop hook today that surfaces .hover/ health (deterministic lint); turning it into a hard spec gate is a few lines more.
3. PostToolUse[crystallize_spec] → replay the moment it's saved
Set the matcher to mcp__hover__crystallize_spec. The instant the agent saves a spec, the hook replays it once to confirm it's green — a record == replay self-check — and git adds it. It reinforces the one rule that makes the whole model work: what got saved is what runs. A spec that can't replay clean never survives to the commit.
4. UserPromptSubmit → a guard-first nudge
When your prompt looks like new behavior (add a checkout flow, build the settings page), the hook injects a nudge: declare the contract first with /mcp__hover__guard, then /mcp__hover__build to drive it to green — so the feature lands with a regression, not just code. It's lightweight and conservative (a verb-plus-feature-noun heuristic, so it doesn't nag), and it pairs with the guard-first loop. hover-hook install wires this.
5. PreToolUse[Bash git push] → block a push while specs are drifted
The strict one, off by default. Match PreToolUse on Bash(git push*); if the heal queue still has drift, return permissionDecision: "deny" with a reason. Nothing leaves the machine while the regression is red. Some teams want that hard edge; most are happy with the Stop gate.
Wire it
npm i -g @hover-dev/mcp@latest
hover-hook install # in your repo — SessionStart / UserPromptSubmit / Stop
Reload Claude Code to activate. Everything above runs with zero AI and no browser except the specs themselves; a hook that errors prints {} and exits 0, so it never wedges your session. The hooks reference has the details, and the shape of the loop these hooks enforce is the regression-test workflow.
Try Hover on your own app.
Add Hover’s MCP to the coding agent you already run. It explores your app and crystallizes plain Playwright specs you own.
npm i -g @hover-dev/mcp && claude mcp add hover -- hover-mcpRead the quick start →