Files
gravl/docs/plans/2026-02-21-stop-hook-design.md
T
clawd c8696123ea docs: add Stop hook design doc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 18:45:43 +01:00

1.7 KiB

Stop Hook Design

Date: 2026-02-21 Scope: Project-level Claude Code hooks for Gravl

Goal

Prevent Claude from stopping mid-session without completing its work. Two enforced conditions:

  1. No uncommitted changes to tracked files
  2. No unresolved conversational TODOs or promises

Approach

Two parallel hooks registered in .claude/settings.json under the Stop event. Both run every time Claude considers stopping.

Hook 1 — Git Clean Check (command)

File: .claude/hooks/git-clean-check.sh

Uses git diff --name-only HEAD to detect modified tracked files that were not committed. Untracked files (e.g. frontend/dist/, planning docs) are intentionally ignored to avoid false positives.

  • Exit 2 + JSON to stderr → blocks Claude from stopping, feeds reason back
  • Exit 0 + JSON to stdout → approves

Hook 2 — Conversation TODO Check (prompt)

A prompt hook that reads the conversation transcript and looks for unresolved work: phrases like "I'll fix X later", "TODO:", "we should also…", or any task Claude mentioned but did not complete. Returns approve or block with a list of unresolved items.

File Layout

.claude/
  settings.json           # Hook registration
  hooks/
    git-clean-check.sh    # Git dirty state check

Decisions

  • Modified tracked files only (not untracked): frontend/dist/ and .planning/ untracked files would cause constant false positives with a full git status --porcelain check.
  • Prompt hook for TODOs (not grep): The goal is conversational promises, not code comments. A prompt hook reads the transcript and can reason about intent.
  • Project-level, not plugin: These checks are specific to Gravl's GSD commit workflow; no plugin abstraction needed.