Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions .claude/skills/comment-checker-setup/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
name: comment-checker-setup
description: Set up or repair a comment-checker PostToolUse hook. Use when comment-checker does not resolve or 'comment-checker did not run' appears on edits, or a flake/direnv/npm install path must be verified. Triggers on: 'comment-checker setup', 'hook not running', 'doctor the comment checker'. Do not use for comment-writing advice or unrelated hook debugging.
---

# comment-checker-setup

Install and verify the comment-checker `PostToolUse` hook so every edit is checked. A hook that cannot resolve its binary checks nothing: it must either find `comment-checker` on PATH or reach it through the direnv bridge, and the whole chain must be proven with the bundled doctor, never by eyeballing a shell.

## When to Activate

```yaml
- id: A1
title: Activate on setup or repair intent
do: activate when the task is installing, wiring, or diagnosing the comment-checker hook, or when 'comment-checker did not run' appears on edits
dont: activate for comment-style feedback on code you are writing, or for generic hook debugging unrelated to comment-checker
check: the request names the hook, the binary, or the 'did not run' symptom
- id: A2
title: Boundary - do not activate for comment writing advice
do: for advice about which comments to write or remove, note that comment-checker itself (called as the hook) is the authority and stop
dont: apply this skill's setup workflow to comment-content questions
check: the ask is about wiring, not about a specific comment's merits
```

## Workflow: provision and verify

```yaml
- id: W1
title: Run the doctor first
do: run `./scripts/doctor.ts [project-dir]` from a clean environment (no ambient dev-shell PATH), and let its output drive the fix
dont: skip the doctor and hand-edit PATH or directories on suspicion; a resolution failure is traced, not guessed
check: the doctor exits 0, or each broken check carries a fix hint you applied
- id: W2
title: Resolve binary on PATH first
do: ensure `comment-checker` resolves on PATH (npm global install, or a dev shell that provides it); `command -v comment-checker` from a clean shell must print a path
dont: rely on a dev shell you are not provably inside; hook subprocesses do not inherit your interactive shell's direnv state
check: `env -i PATH=/usr/bin:/bin sh -c 'command -v comment-checker'` finds it, or the direnv bridge covers the gap
- id: W3
title: Wire the direnv bridge when the repo is flake-based
do: when the project has a flake.nix that provides the binary, add `.envrc` containing `use flake` and run `direnv allow`; the hook falls back to `direnv exec` when PATH misses
dont: stop at `direnv allow` -- a blocked .envrc loads nothing, so verify with `direnv exec . command -v comment-checker`
check: the doctor's direnv bridge check reports [ok]
- id: W4
title: Prove the exit-code contract
do: feed a restating-comment payload and a clean payload to the binary and assert exit 2 and exit 0 respectively (the doctor does this)
dont: accept 'the binary runs' as 'the hook works' -- presence is not the contract
check: the doctor's exit-code contract check reports [ok]
- id: W5
title: Name the real provider in the final report
do: state which provider the project uses (npm global, direnv+flake, or nix develop) and that the doctor verified it end-to-end
dont: leave the resolution mechanism implicit or report 'verified' without the doctor run
check: the report names the provider and cites the doctor exit code
```

```bash
# exact commands for W2-W4 (run from the project root)
env -i PATH=/usr/bin:/bin sh -c 'command -v comment-checker' # W2 path probe
printf 'use flake\n' > .envrc && direnv allow # W3 wiring
direnv exec . command -v comment-checker # W3 verify
```

## Common failures

```yaml
- id: F1
title: Ambiguous PATH shadowing
do: when the doctor's identity check fails, treat 'a different program named comment-checker' on PATH as the cause and remove/reorder it
dont: assume the shadowing binary is the real checker just because it answers
check: the doctor's binary identity check reports the expected `claude-code-comment-checker <semver>` line
- id: F2
title: Blocked .envrc
do: when the direnv bridge fails with 'is blocked', run `direnv allow` and re-run the doctor
dont: edit .envrc contents to make the error go away
check: `direnv exec . command -v comment-checker` resolves
- id: F3
title: Hook file missing
do: when the doctor reports no hook wiring, install the plugin or add the PostToolUse entry to `.claude/settings.json`
dont: ship a binary with no hook attached and call the setup done
check: the doctor's hook wiring check reports [ok]
```

## Verification

```yaml
- id: V1
title: Doctor is the gate
do: run `./scripts/doctor.ts .` and require exit 0 before claiming the hook works
dont: claim 'the comment checker is set up' from a PATH or directory listing alone
check: the doctor prints 'all checks passed' and exits 0
- id: V2
title: Doctor scripts stay green
do: after any edit to `scripts/doctor.ts`, run `deno check doctor.ts && deno lint doctor.ts` (in `scripts/`)
dont: ship a doctor that does not typecheck or lint clean
check: both `deno check` and `deno lint` exit 0 in the scripts directory
```

## Scripts

| Script | Purpose | When to run |
|--------|---------|-------------|
| `scripts/doctor.ts` | Probes resolution, identity, contract, hook wiring, direnv bridge, flake dev shell; exits 0 all-pass, 1 broken | First, and after every fix |

## References (load on demand)

| Reference | When to load (intent) | Hash |
|-----------|--------------|------|
| `references/setup-resolution.md` | Resolve which provider path applies, or when PATH/direnv/nix ordering matters | `5bed20` |

## Integration

```yaml
- id: I1
title: Coordinate with the agent-harness design
do: when the harness that runs the hook needs a path or env change, design it together with this skill's wiring (one change, not two)
dont: treat the hook wiring as isolated from how the harness spawns subprocesses
check: the resolution falls out of the harness's own env, not a workaround
```

## Critical Rules at Document End

```yaml
- id: END1
title: A hook that does not resolve checks nothing
do: prove resolution and the exit-code contract with the doctor from a clean environment before trusting the hook
dont: trust a shell you happened to be in, or a direnv state you did not verify
harm: an unverified hook silently checks zero edits, and the failure is invisible until bad comments ship
check: `./scripts/doctor.ts .` exits 0 from a clean env
- id: END2
title: Never edit the body to chase a failing eval
do: when a check fails, attribute the cause (resolution, identity, wiring) from the doctor's output and fix that, not the skill text
dont: weaken the skill's rules because a fixture fails
harm: editing the skill on an unattributed failure ships the drift
check: every body edit traces to a diagnosed cause, not to a failing run
```

## Do not use for

- Writing or judging code comments in your own work — invoke the checker as the hook does.
- Debugging hook subprocess env unrelated to comment-checker (PATH drop, plugin host) — that is the agent-harness-design skill's surface; cross-reference by capability, never by name.
56 changes: 56 additions & 0 deletions .claude/skills/comment-checker-setup/evals/evals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[
{
"id": "resolve-path",
"prompt": "comment-checker does not resolve when the hook runs, though it works in my shell. What is the first step the fix workflow prescribes?",
"needles": [
"W1",
"doctor"
]
},
{
"id": "blocked-envrc",
"prompt": "The hook reports 'comment-checker did not run' and direnv says the .envrc is blocked. After allowing it, what does the skill's common-failure check run to verify?",
"needles": [
"F2",
"direnv exec . command -v comment-checker"
]
},
{
"id": "identity-shadow",
"prompt": "A binary named comment-checker responds on PATH, but examining it reveals it is not the checker this skill assumes. What exact output contract does the skill's identity check require?",
"needles": [
"claude-code-comment-checker",
"semver"
]
},
{
"id": "doctor-run",
"prompt": "You wired the hook but want proof it actually checks edits, the way the skill's verification section demands. What artifact and what exit does the gate require?",
"needles": [
"doctor.ts",
"exit 2",
"V1"
]
},
{
"id": "flake-direnv-wiring",
"prompt": "A flake.nix provides the checker. The skill's W3 workflow names two exact steps that complete the direnv wiring. What are they?",
"needles": [
"W3",
"direnv allow",
"direnv exec . command -v comment-checker"
]
},
{
"id": "negative-trigger-comment-advice",
"prompt": "Is this comment restating the code? // increments counter next to counter += 1",
"should_not_trigger": true,
"needles": []
},
{
"id": "negative-trigger-other-hook",
"prompt": "My lint hook subprocess drops PATH but is unrelated to comment-checker. What do I do?",
"should_not_trigger": true,
"needles": []
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Setup resolution: which provider path applies

Decide how the project provisions `comment-checker`, then verify with the doctor.

## The provider paths

| Provider | When it applies | Resolves when | Common failure |
|----------|-----------------|---------------|----------------|
| npm global | Any project; no flake needed | package manager bin dir is on PATH | global bin dir outside PATH (`pnpm bin -g` / `npm bin -g`) |
| direnv + flake | Project has `flake.nix` providing the checker | `.envrc` = `use flake` and `direnv allow` ran | `.envrc` blocked; `direnv allow` never run |
| `nix develop` | Ad-hoc shell entry | the dev shell is active | someone trusts an ambient PATH that is not the shell's |

The hook resolves PATH first, then `direnv exec "$CLAUDE_PROJECT_DIR"`. When PATH misses and no `.envrc` exists, nothing checks the edit — the hook exits 1 with the "did not run" error.

## Path-resolution traps

1. **Ambient direnv state contaminates probes.** A shell that already loaded a dev shell makes `command -v` succeed even when the hook's clean subprocess would miss. Probe with `env -i PATH=/usr/bin:/bin sh -c 'command -v comment-checker'`.
2. **A shadowing binary passes `command -v` but not identity.** The real binary prints `claude-code-comment-checker <semver>` to `--version`. Any other output means a different program owns the name on PATH.
3. **A blocked `.envrc` loads nothing.** `direnv allow` is per-clone state; the doctor's direnv bridge check distinguishes "not installed" from "installed but blocked".

## The one invariant

A hook's resolution must be proven from a clean environment, the same one the hook subprocess runs in — never from the interactive shell you happen to be in.
12 changes: 12 additions & 0 deletions .claude/skills/comment-checker-setup/scripts/deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"lock": "./deno.lock",
"tasks": {
"check": "deno check doctor.ts",
"lint": "deno lint doctor.ts"
},
"imports": {
"@std/cli": "jsr:@std/cli@^1.0.32",
"@std/fs": "jsr:@std/fs@1.0.19",
"@std/path": "jsr:@std/path@1.1.6"
}
}
47 changes: 47 additions & 0 deletions .claude/skills/comment-checker-setup/scripts/deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading