Skip to main content

pre-commit-review

ADVISORY pre-commit review that orchestrates parallel single-obsession rule hunters, an over-abstraction skeptic, and a comment critic against the diff. Spawns read-only agents (rule-hunter, overabstraction-skeptic, comment-critic); NEVER edits code. Invoked by @linter-driven-development (Phase 4), by @refactoring (after pattern application), or manually for standalone code review. Categorizes findings as Bugs, New Practice (when in Rome), Design Debt, Readability Debt, or Polish Opportunities. Does NOT block commits.

跳到安装

来源信息

仓库
buzzdan/ai-coding-rules
最近来源活动
2026年9月23日 10:34
检测到的 SKILL.md 语言
英语
星标
4
分支
1

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
2 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
pre-commit-review
description
ADVISORY pre-commit review that orchestrates parallel single-obsession rule hunters, an over-abstraction skeptic, and a comment critic against the diff. Spawns read-only agents (rule-hunter, overabstraction-skeptic, comment-critic); NEVER edits code. Invoked by @linter-driven-development (Phase 4), by @refactoring (after pattern application), or manually for standalone code review. Categorizes findings as Bugs, New Practice (when in Rome), Design Debt, Readability Debt, or Polish Opportunities. Does NOT block commits.
allowed-tools
["Read","Grep","Bash","Agent"]
<objective> Verify a finished diff against the plugin's rules (R1–R12) with evidence, by orchestrating parallel single-obsession rule hunters, one over-abstraction skeptic and one comment critic — the agents `linter-driven-development:rule-hunter`, `linter-driven-development:overabstraction-skeptic` and `linter-driven-development:comment-critic`, spawned by those names and no others. Pure orchestration and reporting: this skill spawns agents and reports; it never edits code, never fixes findings, never blocks a commit. Rule knowledge lives once in `../../rules/`; agents get the path of their rule and read it themselves in their first turn — the parent never pastes a rule, and agents do not invoke skills. Each step's long form is in `reference.md` here, read by `sed` range inside a Bash call the step already makes — never the file whole, never a call of its own — except the report's, read once before writing. </objective> <timing> Run pre-commit, per completed vertical slice — NEVER mid-implementation: GREEN-step TDD code is supposed to look under-designed. The REFACTOR step's per-cycle greps are the mid-implementation net; this pass is the verification net on finished work. </timing> <inputs> - **Diff scope**: the caller's resolved file list or diff range — an explicit argument, else the working tree's changes against `HEAD` (`git diff --name-only HEAD -- 'detected-language source'` plus untracked files), else the branch against its base, and the whole repository only when asked for explicitly. Never widened here; an empty scope is reported as "nothing to review", never as a clean verdict. - **Mode**: `FULL` (first run) or `INCREMENTAL` (re-run after fixes; needs the previous report's findings). </inputs> <protocol> <step_1_grep_prefilter> In-context, cheap, no agents yet. One Bash command prints the **Falsifying questions** section of every rule file, and this skill's hunt-focus table beside it — `for f in <rules dir>/R*.md; do echo "==> $f <=="; sed -n '/^## Falsifying questions/,$p' "$f"; done; sed -n '/^## Hunt focus/,/^## Waiting for agents/p' <this skill dir>/reference.md` — that section only, never a whole rule and never twelve Read calls; then run the detection commands there against the diff scope (changed files only). The commands live in the rule files (`../../rules/R1-…` to `R12-….md`); never restate them. A rule with zero hits is skipped — no hunter for it. Also in-context: a new suppression directive in the diff — the language's form of `# noqa`, `# type: ignore`, `eslint-disable`, `#[allow(...)]`, `@SuppressWarnings`, or whatever the repository's linter documents — or a new exclusion in the linter's configuration file is itself a finding — the change must justify, with evidence, that the rule genuinely does not apply. Also in-context — the **when-in-Rome check**: anything the diff introduces that the repo does not already use (a new test mechanism, a dependency in `the language's project manifest`, a tool or config file, a convention-file edit bundled into a feature diff, a layout unlike its siblings) is a 🟠 finding when a grep of the repo *outside* the diff shows zero prior use; the fix is a discussion or a separate PR, never silent inclusion. </step_1_grep_prefilter> <step_2_spawn_hunters> **Write the scope bundle first**, only when the scope is not empty, in one Bash command into `B=$(mktemp -d)`: - `files.txt` — the scope, one path per line. A file left out of `scope/` keeps its line with the reason: `(not bundled: deleted)`, `(not bundled: binary)` (`grep -Il . -- "$f"` prints nothing), `(not bundled: <n> lines)` over about 2000, `(not bundled: generated)` by the repository's markers. Hunters read those as ground their commands cover and nothing reads whole. Nothing else is filtered. - `diff.patch` — on a scoped review, `git diff <range> -- 'detected-language source'`; untracked files have no diff and appear only under `scope/`; `--all` has no diff. - `scope/<path>.txt` — one per bundled file, at its source path, a `==> <path> <==` header then the text with its own line numbers, so a finding read from the bundle anchors like a `grep -n` hit: `while IFS= read -r f; do mkdir -p "$B/scope/$(dirname "$f")"; { printf '==> %s <==\n' "$f"; cat -n -- "$f"; } > "$B/scope/$f.txt"; done < bundled.txt` - `dirs.txt` — on `--all`, the source directories with file and line counts, for the hunters' reading orders. The same Bash call prints `sed -n '/^## Waiting for agents/,/^## The merged report/p' <this skill dir>/reference.md` — how agents are waited for, what each returns and what their verdicts do — so steps 2, 3 and 3b cost no read of their own. The bundle is the only file this review writes; hunters and the critic get its path, the skeptic does not. For every rule with hits, spawn one rule-hunter, as **foreground** `Agent` calls (`run_in_background: false`) issued together in one message, so they run in parallel and return in it. Never wait any other way — no polling, monitor or wake-up, no second spawn of a call answered "Async agent launched"; its result arrives by itself ("Waiting for agents", read above). Each spawn prompt MUST contain: 1. **The rule file's absolute path** — the hunter's whole rulebook, read in its first turn. Never the text pasted; never two rules per hunter; the parent reads no rule to build a prompt (step 1 printed only the questions). 2. **The bundle's absolute path** and the diff scope it holds. On `--all`, also this hunter's **reading order**: `dirs.txt` with this rule's pre-filter hits first, most hits first, ties by line count ascending, then the rest — no two hunters truncate at the same tail. 3. **That rule's pre-filter hits**, as starting leads, never a limit. Every path is absolute (the hunter runs in the reviewed project's cwd): resolve `../../rules/R<N>-….md` and any case file the rule cites from this skill's own location, then `ls` every resolved path before spawning — listing is not reading; a path that does not list is fixed here, never handed to a hunter. Each hunter returns finding blocks (`rule | file:line | evidence | fix pattern | effort`), one receipt per falsifying question (`Q<n>: <hits> hit(s) → <findings> finding(s)`), a tally and, when its budget ended the hunt, a `not reached:` line — receipts stay whole because the detection commands ran over the whole scope. A question with no receipt was not run ("Hunter output", read above). </step_2_spawn_hunters> <step_3_skeptic_pass> Collect every type/package-extraction finding — R1/R2/R4 "create a type/package", R10 "Extract Synchronized Owner", R11 "Interface Dispatch" / "Strategy Map" — and spawn one overabstraction-skeptic, foreground, in a message with no hunters in it, after every hunter result is in hand; the critic (step 3b) shares that message. Its spawn prompt MUST contain: 1. The extraction findings under review — the hunter blocks pasted verbatim. 2. The absolute path of `../../rules/R1-primitive-obsession.md` and the range it reads: `sed -n '/^### Juiciness scoring/,/^### Placement/p'`. Never the file whole. 3. The absolute path of `../../examples/overabstraction-cidr.md`; with R11 dispatch proposals under review, also `../../examples/anti-if-dispatch.md` and `../../examples/switch-to-polymorphism.md`. No bundle: the skeptic verifies call sites across the whole repository. Its verdicts (`CONFIRMED (score N …)`, `CONFIRMED (score N, judgment call) — alternative: …`, `REFUTED (score N …) → cheaper alternative`, `N/A (R2 mechanism)`, `skeptic: not reached`) are carried into the report verbatim, score included. What never goes to it (R2's construction mechanics, non-extraction findings) and what each verdict does: "Skeptic verdicts", read in step 2. </step_3_skeptic_pass> <step_3b_comment_critic> When the diff contains comment lines — prefilter: `git diff --cached -- 'detected-language source'` filtered to added lines that carry the language's comment marker (`//`, `#`, `/*`, `--`, a docstring opener), minus directive lines — compiler pragmas, build tags, the linter's suppression directive, doc-test output markers (any hit qualifies; directives don't count) — spawn one comment-critic in the same hunter-free message as the skeptic (alone when no skeptic runs), foreground; its sweep is the longest pass of the review and is waited for only by the call returning. Its spawn prompt MUST contain: 1. The absolute path of `../../rules/R9-repo-brain.md` and the range of its **Comment policy** section: `sed -n '/^### Comment policy/,/^### Edge conventions/p'`. 2. The absolute path of `../documentation/reference.md` and the range of its **Comment Value Toolbox** catalog: `sed -n '/^## Comment Value Toolbox/,/^## Frontmatter Templates/p'`. Neither file is read whole. 3. The absolute path of `../../examples/private-comment-noise.md`. 4. The diff scope and the bundle's absolute path — when this review wrote one; a caller without a bundle omits it, and the critic builds its scope in its first turn. It returns per-comment verdicts (`KEEP / TRIM / REWRITE / DELETE`, `DELETE → route R3`) with evidence and replacement text, and a tally; non-KEEP verdicts are 🟡 Readability Debt ("Critic verdicts", read in step 2). </step_3b_comment_critic> <step_4_merged_report> Before writing, read `reference.md`, `sed -n '/^## The merged report/,$p'` — the cluster pass, the category map, the line shape, the reconciliation and the worked example — once, now. The contract it spells out, kept whatever the scope: - **Clusters first.** Before categorizing, list the anchors: group every hunter finding — kept, refuted by the skeptic, or never sent to it — by the named thing it is about (a type, a function, a discriminator, a package), never by line. An anchor converges when ≥2 findings from different rules, or from different falsifying questions of one rule, land on it — exported nilable fields, a method re-checking them and a null handed to the constructor are three R2 questions on one type, one missing constructor. Render every converged anchor, two findings or twenty, as its own entry above the categories, titled with the anchor itself: ``` 🔗 CLUSTER: Alert.Channel — R1, R11, R2, R7 Convergence: 4 findings — R1 Q1, R11 Q2, R2 Q2, R7 Q4 Hypothesis: missing domain concept — a Channel type wants to exist Skeptic: CONFIRMED (score 6) · (or REFUTED → the cheaper alternative, the convergence still real · or no verdict when no extraction was proposed) Routing: design-first — @code-designing (cluster-scoped), then @refactoring ``` The title line carries the anchor and the ids of the rules that converged on it; the pass is not done until each anchor two rules converged on has its entry, and a whole-repository review commonly has six or more. Members still render under their categories, each tagged `[cluster: <anchor>]`. - **Categories**: 🐛 Bugs · 🟠 New Practice · 🔴 Design Debt · 🟡 Readability Debt (R3, R9, the critic's non-KEEP verdicts) · 🟢 Polish (the skeptic's cheaper alternatives). - **One line per finding**: `file:line | R<N> Q<n>: evidence in the question's own words | the move as the rule's Fix pattern spells it | S/M/L`. The fix cell names the move exactly as the Fix pattern section spells it — `Introduce Parameter Object`, `Name enum strings`, `Extract Leaf Type` — and the skeptic's verdict and score follow the move in the same cell: `Introduce Parameter Object: Endpoint — skeptic REFUTED (score 1) → rename dial to Client.dial`. A verdict never replaces the move name with its alternative; a refuted type's alternative also ships as its own 🟢 Polish line. A count is never a finding — `R9 (46 findings)` is forbidden; findings of one shape may share one line naming every anchor. Anchors rendered equal findings returned. - **One physical line, never wrapped.** A finding line and a cluster title line are each one line of text however long — never broken across lines for width. Readers grep the report, and a move name or anchor split over two lines is invisible to them; length is the renderer's problem, not the report's. - **Reconcile**: the header carries each hunter's tally beside its rendered count — `Hunters: R1 8/8 · R9 53/53 (not reached: internal/store) · R4–R6 skipped` — and the two agree, or the dropped finding is rendered, never the tally adjusted. Any agent's `not reached:` line renders verbatim beside its tally, and the Scope line then reads `Mode: FULL · PARTIAL coverage`; without those words the header asserts full coverage. - Fix routing cites each rule's **Fix pattern**; out-of-scope observations go under BROADER CONTEXT; the report ends `Caller decides: commit as-is · fix 🔴 first · fix all. Findings are advisory.` **The report is the message** that ends the review — never a file, never a summary pointing at one, whatever its length. </step_4_merged_report> </protocol> <modes> **FULL:** pre-filter all twelve rules over the whole scope; report every surviving finding. **INCREMENTAL:** scope = the files changed since the last review; run steps 1–3 on it and report the delta against the previous findings — ✅ Fixed (its detection command re-run confirms), ⚠️ Remaining, 🆕 New. </modes> <constraints> This skill MUST NOT: - Edit code, fix findings, or invoke fix skills (@refactoring, @code-designing, @testing) - Write the report, or any part of it, to a file — the bundle is the only file it writes, and an empty scope writes none - Run the linter or tests, or block a commit — every finding is advisory - Restate or paste rule content — spawn prompts name rules by absolute path and range - Spawn anything but the three agents in `<objective>`, or wait for one by polling, monitoring, scheduling or re-spawning </constraints> <who_invokes> @linter-driven-development (Phase 4, per completed slice) · @refactoring (after fixes, INCREMENTAL) · the user (standalone review before commit). </who_invokes>
在 GitHub 查看