08195c1cd4
comms-lint.py and comment-lint.py lived only in ~/.claude, which is not a git repo. Contract prose lived in ~/.claude/CLAUDE.md. Neither survived a machine rebuild. Prose moves to claude-md/ fragments, imported via @name.md. Linters move to hooks/. link.sh and home.nix distribute both. settings.json wiring stays manual — it holds machine-local MCP/statusline config this repo must not own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VaGR6ERGCfzWTtuv2rebGe
41 lines
1.8 KiB
Markdown
41 lines
1.8 KiB
Markdown
# hooks
|
|
|
|
Claude Code hooks. Claude-only — Codex ignores. `bin/link.sh` / `nix/home.nix` symlink these into `~/.claude/hooks/`; **wiring is manual**, see below.
|
|
|
|
| hook | event | what |
|
|
|------|-------|------|
|
|
| `comms-lint.py` | `PreToolUse` / `Bash` | Gates `gh issue\|pr create\|edit\|comment\|review`. Lints body against `claude-md/public-comms.md` (BLUF, ≤300 words above fold, ≤4 bold spans, no essay headings, table for 3+ options). Exit 2 blocks, stderr becomes feedback. |
|
|
| `comment-lint.py` | `PostToolUse` / `Write\|Edit\|MultiEdit` | Lints newly-added comment lines in code files against `claude-md/code-comments.md`. Exit 2 = revise nudge (edit already applied). Long-comment-run finding is advisory, delivered via `additionalContext`. |
|
|
|
|
Both fail open on anything they can't parse. Debug with `COMMS_LINT_DEBUG=1` / `COMMENT_LINT_DEBUG=1`.
|
|
|
|
## Wiring
|
|
|
|
`~/.claude/settings.json` is machine-local (MCP servers, statusline, per-box hooks), so this repo does not own it. Merge into `.hooks`:
|
|
|
|
```json
|
|
{
|
|
"hooks": {
|
|
"PreToolUse": [
|
|
{ "matcher": "Bash",
|
|
"hooks": [{ "type": "command", "command": "~/.claude/hooks/comms-lint.py" }] }
|
|
],
|
|
"PostToolUse": [
|
|
{ "matcher": "Write|Edit|MultiEdit",
|
|
"hooks": [{ "type": "command", "command": "~/.claude/hooks/comment-lint.py" }] }
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Contract prose lives in `claude-md/`, linked to `~/.claude/<name>.md` and imported from `~/.claude/CLAUDE.md` via `@public-comms.md` / `@code-comments.md`. Both linters cite those paths in their block message — moving a fragment means updating the linter string too.
|
|
|
|
## Testing a hook
|
|
|
|
Feed it the payload shape Claude Code sends:
|
|
|
|
```sh
|
|
echo '{"tool_name":"Bash","tool_input":{"command":"gh pr comment 1 --body \"short\""}}' \
|
|
| ~/.claude/hooks/comms-lint.py; echo "exit=$?"
|
|
```
|