Skip to content

Deploy agent hooks: Claude PostToolUse/Stop + Cursor rules#94

Merged
michaelbarton merged 13 commits into
masterfrom
deploy-agent-config
Jun 12, 2026
Merged

Deploy agent hooks: Claude PostToolUse/Stop + Cursor rules#94
michaelbarton merged 13 commits into
masterfrom
deploy-agent-config

Conversation

@michaelbarton

Copy link
Copy Markdown
Owner

Summary

  • Ansible plumbing: new agent_hooks task symlinks claude/settings.json into ~/.claude/ and cursor/rules/ into ~/.cursor/, plus the initial Cursor rules (planning, dbt).
  • Claude hooks (command-type, path-gated):
    • plan-review.sh fires only for edits under .cursor/plans/ or .claude/plans/, then injects a strict plan-quality checklist.
    • stop-check.sh fires only when the current turn edited a .sql inside a dbt project (dbt_project.yml ancestor) or any .qmd, AND no build/render command ran.
  • Both scripts referenced via $HOME/... for portability across machines/accounts.

The hooks replace earlier prompt-type variants whose sub-models narrated past their own stated gate (flagging non-matching edits anyway). Command hooks make the gate deterministic — match or silent exit.

Test plan

  • Local unit tests of both hook scripts against synthetic transcripts (match / non-match / build-ran-this-turn).
  • Verified $HOME expansion in sh -c invocation.
  • Confirmed git tracks the executable bit (100755) on both .sh files.
  • After merge, rerun ansible-playbook ansible/dotfiles.yml --tags hooks on a fresh box and confirm both symlinks land.
  • Trigger a plan-document edit and confirm plan-review.sh injects the checklist.
  • Trigger a .sql edit inside a dbt project with no dbt build and confirm stop-check.sh reminds.

Dependency note: scripts require jq, which is already assumed by other dotfiles utilities (preview_hocon, grafana/query_grafana.bash) and provisioned outside this repo.

🤖 Generated with Claude Code

michaelbarton and others added 13 commits May 22, 2026 22:56
Adds an agent_hooks task that links the in-repo `claude/settings.json`
into `~/.claude/` and the `cursor/rules` directory into `~/.cursor/`, so
both agents pick up shared config from this dotfiles checkout. Includes
the initial set of Cursor rules (planning, dbt).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two command-type hooks replace earlier prompt-type hooks that would
narrate past their own stated gate (e.g. flagging a JSON config edit as
"a YAML build artifact"). Command hooks make the path filter
deterministic in shell — the gate either matches or the script exits
silently, no model interpretation involved.

- `plan-review.sh` (PostToolUse on Write|Edit): only fires when the
  edited file is under `.cursor/plans/` or `.claude/plans/`. On a match,
  injects a strict plan-quality checklist as additional context.
- `stop-check.sh` (Stop): only fires when the current turn edited a
  `.sql` file inside a dbt project (has a `dbt_project.yml` ancestor)
  or any `.qmd` file, AND no build/render command ran. Suggests the
  matching command per file group.

Both scripts are referenced via `$HOME/...` so the deployment is
portable across machines and accounts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extracts the inline heredoc out of `plan-review.sh` into a dedicated
markdown file so the prompt picks up editor/formatter support and so
future prompts can sit alongside it under `claude/prompts/`. The script
resolves the file relative to its own location, so it remains portable
across machines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously `plan-review.md` and `planning.mdc` each restated the same
five core gates (exit criteria, invariants, failure modes + premortem,
assumptions & unknowns, outside view) plus the conditional reversibility
and System 2 gates. Editing one and forgetting the other would silently
drift the contract.

The hook script now reads `cursor/rules/planning.mdc` (strips its YAML
frontmatter) and substitutes its body into the `{{PLANNING_RULE}}`
placeholder in `plan-review.md`. `plan-review.md` keeps only the audit
framing and the `PLAN OK` / gap-list output contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `claude/prompts/plan-review.md` template only held ~10 lines of
audit framing + an output contract wrapping a `{{PLANNING_RULE}}`
placeholder. Claude Code has no convention for a `prompts/` directory,
and the substitution loop was more indirection than the content
deserves. Inlining the framing as two small heredocs around the
canonical `planning.mdc` body keeps the single-source-of-truth
property and drops a file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes from `cursor/rules/planning.mdc`:
- "Reversibility" and "System 2 triggers" conditional gates — these are
  geared at production deploys / data migrations rather than the
  analytical/dbt work that's the actual day-to-day.
- "Three-tier boundaries for actions" — overly prescriptive, and the
  "Never do" list in particular bakes in dbt-shop-specific anti-patterns
  that don't generalize.

Five core gates (exit criteria, invariants, failure modes + premortem,
assumptions & unknowns, outside view), minimal viable change, viz
confirmation, and plan format all retained.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plan-review audit prompt now follows judge-prompt best practice:
named gates, per-gate PASS/FAIL/N-A verdicts with quoted evidence,
strict default on uncertainty, XML-delimited rule body, and the full
rule injected every edit (session marker went stale after compaction).

Stop-check nag spells out what verification means and gives an honest
exit for false positives. New track-tool-use.sh records this turn's
edits/commands to a state file so stop-check can target dbt/quarto
files without parsing the transcript.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sions

planning.mdc: plans for new/changed dbt models must declare the grain
(operator-reviewed spec, not implementation-discovered) and exit via a
passing uniqueness test on it. dbt.mdc: grain test required per model,
failing grain tests are findings (never widen keys or dedup to pass),
all dedup must be plan-sanctioned, marts need a reconciliation test
against an externally controlled number.

New dbt-rules.sh hook mirrors Cursor's glob-scoped rule loading for
Claude Code: injects dbt.mdc on the first .sql/.yml edit inside a dbt
project per session, then a compressed reminder of the load-bearing
rules on later edits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@michaelbarton michaelbarton merged commit 2b268e0 into master Jun 12, 2026
2 checks passed
@michaelbarton michaelbarton deleted the deploy-agent-config branch June 12, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant