@olegkoval/agent-skills 1.26.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.claude-plugin/plugin.json +2 -1
  2. package/README.md +7 -3
  3. package/catalog/skills.json +18 -0
  4. package/package.json +5 -3
  5. package/packages/software-development/lekker-review/SKILL.md +519 -0
  6. package/packages/software-development/lekker-review/adapters/claude/plugin.json +5 -0
  7. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/SKILL.md +520 -0
  8. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/completeness-critic.md +21 -0
  9. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/conventions.md +124 -0
  10. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fix-verifier.md +84 -0
  11. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/fixer.md +120 -0
  12. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/implementation.md +53 -0
  13. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/prover.md +135 -0
  14. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/quality.md +72 -0
  15. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/simplification.md +45 -0
  16. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/test-quality.md +170 -0
  17. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-logic.md +27 -0
  18. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/triage-quality.md +41 -0
  19. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/agents/verifier.md +295 -0
  20. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/artifact-page.md +143 -0
  21. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/context-gathering.md +162 -0
  22. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/fix-mode.md +329 -0
  23. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/github-post.md +205 -0
  24. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/house-rules.md +76 -0
  25. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/references/output-format.md +232 -0
  26. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/changed-files.sh +77 -0
  27. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/setup-worktree.sh +337 -0
  28. package/packages/software-development/lekker-review/adapters/claude/skills/lekker-review/scripts/verify-fixes.sh +231 -0
  29. package/packages/software-development/lekker-review/fix-workflow.js +273 -0
  30. package/packages/software-development/lekker-review/references/agents/completeness-critic.md +21 -0
  31. package/packages/software-development/lekker-review/references/agents/conventions.md +124 -0
  32. package/packages/software-development/lekker-review/references/agents/fix-verifier.md +84 -0
  33. package/packages/software-development/lekker-review/references/agents/fixer.md +120 -0
  34. package/packages/software-development/lekker-review/references/agents/implementation.md +53 -0
  35. package/packages/software-development/lekker-review/references/agents/prover.md +135 -0
  36. package/packages/software-development/lekker-review/references/agents/quality.md +72 -0
  37. package/packages/software-development/lekker-review/references/agents/simplification.md +45 -0
  38. package/packages/software-development/lekker-review/references/agents/test-quality.md +170 -0
  39. package/packages/software-development/lekker-review/references/agents/triage-logic.md +27 -0
  40. package/packages/software-development/lekker-review/references/agents/triage-quality.md +41 -0
  41. package/packages/software-development/lekker-review/references/agents/verifier.md +295 -0
  42. package/packages/software-development/lekker-review/references/artifact-page.md +143 -0
  43. package/packages/software-development/lekker-review/references/context-gathering.md +162 -0
  44. package/packages/software-development/lekker-review/references/fix-mode.md +329 -0
  45. package/packages/software-development/lekker-review/references/github-post.md +205 -0
  46. package/packages/software-development/lekker-review/references/house-rules.md +76 -0
  47. package/packages/software-development/lekker-review/references/output-format.md +232 -0
  48. package/packages/software-development/lekker-review/scripts/changed-files.sh +77 -0
  49. package/packages/software-development/lekker-review/scripts/setup-worktree.sh +337 -0
  50. package/packages/software-development/lekker-review/scripts/verify-fixes.sh +231 -0
  51. package/packages/software-development/lekker-review/workflow.js +602 -0
  52. package/site/assets/paperbag.css +707 -0
  53. package/site/assets/paperbag.js +218 -0
  54. package/site/build.mjs +380 -0
@@ -0,0 +1,329 @@
1
+ # fix-mode.md -- lekker-review `--fix` procedure
2
+
3
+ Run this AFTER the review has been printed and saved to `~/code-reviews/`, and
4
+ ONLY when `FIX_MODE=true` (either `--fix` was passed, or the user answered yes to
5
+ the post-review offer).
6
+
7
+ Fix mode turns verified findings into real commits on the PR branch. It edits
8
+ only the isolated review worktree, never the user's checkout, and it never
9
+ pushes without explicit confirmation.
10
+
11
+ **Never fix and push in the same breath as reporting.** Committing is local and
12
+ reversible; pushing writes to someone else's branch and is outward-facing.
13
+
14
+ ---
15
+
16
+ ## Step 1 -- Preconditions (all must hold, else stop and report)
17
+
18
+ | Precondition | Check | If it fails |
19
+ |--------------|-------|-------------|
20
+ | Worktree exists | `WORKTREE_PATH` non-null and the dir exists | Run `scripts/setup-worktree.sh` now, then continue. Fix mode cannot work from the diff alone. |
21
+ | Worktree is clean | `git -C <WORKTREE_PATH> status --porcelain` is empty | Stop. Report the dirty paths -- something already edited it. |
22
+ | Head still current | `git -C <repoRoot> fetch origin <PR_BRANCH>` then compare `git rev-parse origin/<PR_BRANCH>` to `headSha` | Head moved during the review. Stop, report both shas, tell the user to re-run: the review is stale and fixes could clobber new work. |
23
+ | PR is open | `gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json state,mergedAt` | Stop if MERGED or CLOSED. |
24
+ | PR is not from a fork you cannot write to | `gh pr view --json headRepositoryOwner,maintainerCanModify` | If the head repo is a fork and `maintainerCanModify` is false, fixes can be committed locally but NOT pushed. Say so up front, before spending agents. |
25
+
26
+ The worktree checkout is a **detached HEAD** at `origin/<PR_BRANCH>` (see
27
+ `setup-worktree.sh`). That is intentional -- do not create or check out a
28
+ branch in it. Commits land on the detached HEAD and are pushed with an explicit
29
+ refspec in Step 6.
30
+
31
+ ---
32
+
33
+ ## Step 2 -- Select the findings to fix
34
+
35
+ Eligible finding = severity `critical` or `important`, has a non-empty `fix`
36
+ field, and its `file` exists in the worktree.
37
+
38
+ - Findings without a `fix` field are review-only. List them as "not
39
+ auto-fixable" in the report; never guess a fix.
40
+ - `observation` and `idiomatic` findings are NEVER auto-fixed. They are
41
+ judgment calls and non-blocking by definition.
42
+ - `PR-1` (title prefix) is not a code fix. Never edit the PR title as part of
43
+ fix mode -- it stays a `⛔ CANNOT MERGE` instruction for the author.
44
+ - Skip any finding whose `file` is generated (`*/generated/*`, lockfiles,
45
+ `*.snap`, build output). Report it as skipped-generated.
46
+
47
+ If the user chose "Critical only" at the offer prompt, filter to `critical`.
48
+
49
+ If nothing is eligible: say so in one line and skip to Step 8. Do not run the
50
+ workflow with an empty finding list.
51
+
52
+ Write the selected findings to `<scratchpad>/fix-findings.json` (receipt), then
53
+ state the plan before spending agents:
54
+
55
+ ```
56
+ Fixing <N> finding(s) across <M> file(s): <file list>
57
+ Not auto-fixable: <N> (<reasons>)
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Step 3 -- Run the fix workflow
63
+
64
+ ```
65
+ Workflow tool:
66
+ scriptPath: ${CLAUDE_PLUGIN_ROOT}/fix-workflow.js
67
+ args: {
68
+ repoSlug,
69
+ prNumber,
70
+ worktreePath: "<WORKTREE_PATH>",
71
+ diffFile: "<scratchpad>/pr.diff",
72
+ contextFile: "<scratchpad>/context.json",
73
+ promptDir: "${CLAUDE_PLUGIN_ROOT}/references/agents",
74
+ findings: [ <the selected finding objects, verbatim> ]
75
+ }
76
+ ```
77
+
78
+ Pass `findings` as a real JSON array, not a stringified one. The workflow groups
79
+ by file (one agent per file, so no two agents ever edit the same file), applies
80
+ the fix, then runs a read-only fix-verifier over the actual `git diff`. A
81
+ verdict other than `good` buys exactly one retry, then stops.
82
+
83
+ Return value:
84
+ `{groups, droppedGroups, agentCount, retryCount, outputTokens, turnTokensTotal}`,
85
+ one `groups` entry per file with `results[]`, `filesTouched[]`, `verdict`,
86
+ `problems[]`, `committable`. `outputTokens` is the fix workflow's own spend
87
+ (already excluding the review workflow that ran before it); `turnTokensTotal` is
88
+ the whole turn's pool. Report the former on the `Fix agents:` cost line.
89
+
90
+ If the Workflow tool is unavailable: fall back to launching one Agent per file
91
+ group on `sonnet` with `references/agents/fixer.md`, then one Agent per group
92
+ with `references/agents/fix-verifier.md`. Same rules, same verdict handling.
93
+ State the fallback in the report.
94
+
95
+ ---
96
+
97
+ ## Step 4 -- Revert what did not earn a commit
98
+
99
+ For every group with `committable: false` that touched files:
100
+
101
+ ```bash
102
+ git -C <WORKTREE_PATH> checkout -- <each path in filesTouched>
103
+ ```
104
+
105
+ Then confirm the revert landed:
106
+
107
+ ```bash
108
+ git -C <WORKTREE_PATH> status --porcelain
109
+ ```
110
+
111
+ Only committable groups' files may remain modified. Any leftover untracked file
112
+ from a reverted group gets removed explicitly (`rm -f <path>`), never with
113
+ `git clean -fd` (too blunt for a shared worktree).
114
+
115
+ `harmful` verdicts are a normal outcome, not a failure of the run: the finding
116
+ simply stays a review comment for the author. Report it as such.
117
+
118
+ ---
119
+
120
+ ## Step 5 -- Verify the fixed tree (fresh post-condition)
121
+
122
+ ```bash
123
+ ~/.claude/skills/lekker-review/scripts/verify-fixes.sh \
124
+ <WORKTREE_PATH> <scratchpad>/fix-verify.json tests
125
+ ```
126
+
127
+ Pass `tests` only when the diff touched logic and the repo has a `test` script;
128
+ pass `no-tests` for doc/config-only fixes or when the suite needs live infra.
129
+
130
+ Read the JSON and compare against the pre-fix baseline in `worktree.json`:
131
+
132
+ - `tscChangedTail` / `tscErrorCount` -- compare against the same two baseline
133
+ keys. `tscChangedTail` is the attributable set (errors in files this branch
134
+ touched, which now includes the files the fix agents wrote); an entry there
135
+ that is not in the baseline was introduced by the fixes. A rise in
136
+ `tscErrorCount` with no new `tscChangedTail` entry means the fix broke a file
137
+ it does not own - treat that as introduced too. Revert the offending group's
138
+ files (Step 4) and mark those findings `failed`. Never commit a tree with
139
+ newly-introduced type errors.
140
+ - `eslintTail` -- same comparison. Both runs lint only changed files, so the
141
+ comparison is like-for-like; check `eslintScope` matches the baseline's
142
+ (`changed-files` vs `full-fallback`) before trusting a diff between the two.
143
+ - `testTail` / `testExitCode` -- a newly failing test caused by a fix means
144
+ revert that group. A test that already failed on the baseline head is not
145
+ yours; say so explicitly rather than silently ignoring it.
146
+ - `dirtyPaths` -- must contain only files declared by committable groups. An
147
+ undeclared path is a red flag: revert it and report.
148
+
149
+ If a check was skipped (no `node_modules`, no config), say `skipped` in the
150
+ report. Skipped is a state, not a pass.
151
+
152
+ ---
153
+
154
+ ## Step 5b -- Proof flip (red → green)
155
+
156
+ For every group that is still `committable` after Step 5, collect the
157
+ findings in that group that carry `proof.proven === true` (the
158
+ `<scratchpad>/fix-findings.json` sidecar written in Step 2 has the `proof`
159
+ objects, including `testCode` and `testCommand`, alongside each finding). If a
160
+ committable group has no proven findings, skip it -- there is nothing to flip.
161
+
162
+ For each proven finding in a committable group:
163
+
164
+ 1. **Re-materialize the test**: write `proof.testCode` back to its original
165
+ filename (the same `lekker-proof-<file-slug>-<line>.test.ts` name it was captured
166
+ under) at the worktree root.
167
+ 2. **Run** exactly `proof.testCommand` (Bash `timeout` 120000).
168
+ 3. **Judge**:
169
+ - **PASSES now** -> the fix demonstrably resolves the finding. Record
170
+ `proofFlip: green` for that finding in the Step 8 status table.
171
+ - **STILL FAILS with the same assertion** -> the fix did not fix the bug.
172
+ The group is NOT committable regardless of the fix-verifier's `good`
173
+ verdict -- revert it (Step 4 procedure) and mark its findings `failed`
174
+ with reason `proof still red after fix`. An executed test outranks a
175
+ reviewer agent's opinion.
176
+ - **Fails for a NEW, unrelated reason** (import broke, different error) ->
177
+ the fix likely broke something else; same outcome: revert the group,
178
+ mark its findings `failed`, and quote the new error in the reason.
179
+ 4. **Delete the test file** and verify with `git -C <WORKTREE_PATH> status
180
+ --porcelain` that only the fix edits remain -- no stray proof file, no
181
+ other drift.
182
+
183
+ A group reverted at this step no longer participates in Step 6 (Commit) --
184
+ treat it exactly like a Step 4 revert. Re-run the `git status --porcelain`
185
+ check after any revert triggered here before moving on.
186
+
187
+ ---
188
+
189
+ ## Step 6 -- Commit (local only)
190
+
191
+ One commit per file group, in group order. Stage explicitly -- never `git add -A`,
192
+ never `git add .`:
193
+
194
+ ```bash
195
+ git -C <WORKTREE_PATH> add -- <filesTouched for this group>
196
+ git -C <WORKTREE_PATH> commit -m "<subject>" -m "<body>"
197
+ ```
198
+
199
+ Subject: `<TICKET_PREFIX> review fix: <short label>` where `TICKET_PREFIX` is the
200
+ `[TICKET-NNN]` from the PR title when there is one, omitted otherwise. Keep the
201
+ subject under 72 chars.
202
+
203
+ Body: one `- ` line per applied finding, using the fixer's `summary`, then:
204
+
205
+ ```
206
+ Applied from lekker-review: <REVIEW_FILE>
207
+
208
+ Co-Authored-By: Claude Code <noreply@anthropic.com>
209
+ ```
210
+
211
+ If two groups declared the same file, commit them together as one commit and
212
+ say so in the report.
213
+
214
+ Receipt after committing:
215
+
216
+ ```bash
217
+ git -C <WORKTREE_PATH> log --oneline <headSha>..HEAD
218
+ git -C <WORKTREE_PATH> status --porcelain # must be empty
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Step 7 -- Push (requires explicit confirmation)
224
+
225
+ Show the user, before asking:
226
+
227
+ - the commit list (`git log --oneline <headSha>..HEAD`)
228
+ - the full diffstat (`git diff --stat <headSha>..HEAD`)
229
+ - the per-finding table from Step 8
230
+
231
+ Then ask, in a single question: push these `<N>` commit(s) to
232
+ `<PR_BRANCH>` on `<REPO_SLUG>`, or leave them local?
233
+
234
+ **Unattended runs (cron, `/loop`, background agent): never push, never ask.**
235
+ Stop after Step 6, keep the worktree, and report the worktree path plus the
236
+ exact push command so a human can release it. This matches the standing
237
+ unattended-run rule: stage the artifact, a human releases it.
238
+
239
+ On confirmed push:
240
+
241
+ ```bash
242
+ git -C <repoRoot> fetch origin <PR_BRANCH>
243
+ # guard: origin must still be at the sha we based the fixes on
244
+ git -C <repoRoot> rev-parse origin/<PR_BRANCH> # must equal <headSha>
245
+ git -C <WORKTREE_PATH> push origin HEAD:refs/heads/<PR_BRANCH>
246
+ ```
247
+
248
+ - If the guard sha differs, ABORT the push. Report that the branch moved and
249
+ leave the commits local. Never `--force`, never `--force-with-lease`, never
250
+ rebase someone else's branch.
251
+ - Never push to `main`, `master`, `staging`, or `develop`, whatever the branch
252
+ variables say. Stop if `PR_BRANCH` is one of those.
253
+
254
+ Post-condition (fresh source, not the push output):
255
+
256
+ ```bash
257
+ gh pr view <PR_NUMBER> --repo <REPO_SLUG> --json headRefOid,mergeStateStatus
258
+ ```
259
+
260
+ Confirm `headRefOid` equals the local HEAD sha. Print
261
+ `✓ Pushed <N> commit(s) -> <PR_URL> (head now <new short sha>)`. If it does not
262
+ match, say the push is unconfirmed and stop -- do not retry.
263
+
264
+ Do NOT also post the fixed findings as inline review comments. When `--post` and
265
+ `--fix` both ran, post only the findings that were NOT applied; a comment asking
266
+ for a change you already committed is noise.
267
+
268
+ ---
269
+
270
+ ## Step 8 -- Report and record
271
+
272
+ Print a table:
273
+
274
+ | # | Finding | File | Status | proofFlip | Note |
275
+ |---|---------|------|--------|-----------|------|
276
+ | 1 | <title> | `<file>:<line>` | ✅ applied | green | <fixer summary> |
277
+ | 2 | <title> | `<file>:<line>` | ↩️ reverted | still-red | <verifier problem, or "proof still red after fix"> |
278
+ | 3 | <title> | `<file>:<line>` | ⏭️ skipped | n/a | <reason, e.g. needs cross-file change> |
279
+ | 4 | <title> | `<file>:<line>` | ❌ failed | n/a | <what blocked it> |
280
+
281
+ `proofFlip` is `green` (proof re-ran and passed), `still-red` (proof re-ran and
282
+ still failed, so the group was reverted per Step 5b), or `n/a` (the finding
283
+ carried no `proof.proven === true`, so Step 5b never ran for it).
284
+
285
+ Then append this section to `REVIEW_FILE` (the saved review), so the record and
286
+ the review never drift apart:
287
+
288
+ ```markdown
289
+ ---
290
+
291
+ ## 🔧 Fixes applied
292
+
293
+ **Base:** `<headShaShort>` · **Commits:** <N> · **Pushed:** <yes, head now `<sha>` | no, local only at <WORKTREE_PATH>>
294
+ **Checks:** tsc <clean | N new errors | skipped> · eslint <...> · tests <passed | failed | skipped>
295
+ **Fix agents:** <N> (<retryCount> retried)
296
+ **Proof flips:** <M green / K still-red / rest n/a> *(include only when at least one finding carried `proof.proven === true`)*
297
+
298
+ | # | Finding | File | Status | proofFlip | Note |
299
+ ...same table...
300
+ ```
301
+
302
+ Re-read the file after writing and emit `✓ Fixes recorded -> <REVIEW_FILE>`.
303
+
304
+ Add one line to the `## 💰 Review Cost` block for fix-mode spend:
305
+
306
+ ```
307
+ Fix agents: <N> (sonnet) — <outputTokens> output tokens, ~$<X.XX>
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Step 9 -- Cleanup override
313
+
314
+ The normal cleanup step removes the worktree. In fix mode:
315
+
316
+ - **Pushed successfully** -> clean up as usual.
317
+ - **Commits exist but were not pushed** -> KEEP the worktree and the repo clone.
318
+ Print the path and the push command. Deleting it would destroy the only copy
319
+ of the work.
320
+ - **Nothing was committed** -> clean up as usual.
321
+
322
+ ---
323
+
324
+ ## Failure rules
325
+
326
+ - Two identical failures = stop and diagnose. No loops.
327
+ - Never claim a fix landed without the `git log` / `git status` receipt.
328
+ - Never present the review's proposed `fix` text as though it were applied. Only
329
+ a committed diff counts.
@@ -0,0 +1,205 @@
1
+ # github-post.md -- lekker-review --post flag procedure
2
+
3
+ Execute this procedure AFTER the review file has been saved to `~/code-reviews/`
4
+ and ONLY when the user passed `--post`.
5
+
6
+ ---
7
+
8
+ ## Step 1 -- Build the payload
9
+
10
+ Construct a JSON payload at `/tmp/lekker-post-$$.json` with the structure:
11
+
12
+ ```json
13
+ {
14
+ "body": "<summary section>",
15
+ "comments": [
16
+ {
17
+ "path": "<relative file path>",
18
+ "line": <line number>,
19
+ "side": "RIGHT",
20
+ "body": "<finding title + why + fix in GitHub markdown>"
21
+ }
22
+ ]
23
+ }
24
+ ```
25
+
26
+ Rules:
27
+
28
+ - **Do NOT include an `event` field.** Omitting it creates a PENDING review,
29
+ visible only to the requesting user until they submit it. NEVER submit the
30
+ review programmatically.
31
+ - Include one comment entry for every Critical and Important finding whose
32
+ `file:line` falls within the diff hunks of this PR (see Step 2 for how to
33
+ determine commentability).
34
+ - **Keep every comment body to 2-4 sentences and under ~700 characters**
35
+ (excluding any suggestion block). Inline comments are read one at a time in a
36
+ narrow column; a long one does not get read, so length actively costs you the
37
+ fix. The detail belongs only in the saved review file (`~/code-reviews/*.md`).
38
+ Do NOT reproduce the file's full Critical/Important write-up inline.
39
+
40
+ - **Open with the ask, in the imperative.** The first clause must be the action
41
+ the author takes ("Return early here", "Extract one shared winner-picker",
42
+ "Raise to 250", "Add a double with `session`"). Evidence comes after, and only
43
+ the evidence that makes the ask credible. Never open with a bolded severity
44
+ label, a restated finding title, or a preamble — the author already knows they
45
+ are reading a review comment.
46
+
47
+ ```
48
+ ✗ **Important — two implementations of "largest fulfillment order" with
49
+ different tie-break keys.** This ranks by value → units → id; `x.ts:104`
50
+ ranks by shipped qty → id. Diverging input: one shared line referenced by
51
+ FO-A (qty 1, one $100 item) and FO-B (qty 3, three $10 items) — fallback
52
+ picks FO-A, exact picks FO-B. Because `existingCreatedLines` idempotency is
53
+ keyed per `fulfillmentOrderGid` with no cross-FO check, a transient
54
+ exact-API failure on FO-A (fallback wins, line written) followed by a
55
+ successful retry on FO-B (exact wins, line written) posts the shared charge
56
+ twice. Please extract one `pickSharedChargeWinner(candidates, size, id)`…
57
+
58
+ ✓ Please extract one shared winner-picker used by both files, keyed on FO
59
+ value. This ranks value → units → id; `x.ts:104` ranks shipped-qty → id, so
60
+ FO-A (qty 1, one $100 item) vs FO-B (qty 3, three $10 items) gives A here
61
+ and B there. Idempotency is keyed per `fulfillmentOrderGid` with no cross-FO
62
+ check, so a fallback run that writes A's line followed by an exact-path
63
+ retry on B writes the same charge twice.
64
+ ```
65
+
66
+ - **Cut every clause that does not change what the author does.** In particular:
67
+ no severity prefix (the review body already states the counts), no
68
+ "Why it's wrong:" / "Fix:" headers (that is the saved-file format, not the
69
+ inline format), no verifier reasoning, no restating what the PR does, no
70
+ second worked example once the first lands, and no sentence whose content is
71
+ already visible on the commented line.
72
+ - **Use a GitHub suggestion block for the fix whenever it's a direct code change**
73
+ anchored to the commented line(s) — a reviewer can apply it with one click:
74
+ ```suggestion
75
+ <replacement line(s), exact drop-in for the line(s) the comment is anchored to>
76
+ ```
77
+ Only use a suggestion block when it exactly replaces the commented line(s) —
78
+ never for fixes spanning multiple files or requiring a new function/extraction
79
+ elsewhere. For those, describe the fix in one sentence instead and point to
80
+ the saved review for detail; do not paste a plain fenced code block as a
81
+ substitute for a real suggestion.
82
+ - **Every inline comment must be ACTIONABLE** — it must ask for a concrete change
83
+ (fix X, add a test for Y, regenerate Z). Do NOT post informational-only or
84
+ FYI comments ("behaviour change, intentional", "note that…", "just flagging").
85
+ If there's nothing to do, there's no comment — put context like that in the
86
+ review body or the saved review file, never as an inline PR comment.
87
+ - The review-level `body` field must contain, in this order: the finding counts
88
+ ("0 Critical / 5 Important / 6 Observations / 1 Idiomatic"), one or two
89
+ sentences of risk framing, then **a numbered list of the asks — one line each,
90
+ imperative, matching the inline comments in order**. That list is what the
91
+ author reads first and works from; it must be scannable in ten seconds. Then
92
+ any Production Signals, then a short flat list of Observations marked "no
93
+ action required", then the saved review file path.
94
+
95
+ Keep the body itself under ~2,500 characters. If it is longer, the asks are
96
+ buried — cut prose, never cut the numbered asks.
97
+ - Do NOT prefix the body with a banner like "## Lekker review". Do NOT praise the
98
+ PR or describe what it does well — no "solid", "handled well", "clean", "nice".
99
+ State the risk and the asks only.
100
+ - We use **Linear**, not Jira. Never write "Jira" in any comment or body; refer
101
+ to Linear ticket IDs (e.g. DUBO-201) directly.
102
+
103
+ ---
104
+
105
+ ## Step 2 -- Determine commentability
106
+
107
+ A line is commentable only if it appears in the diff hunks for the file. To
108
+ check, scan `DIFF_FILE` for the relevant hunk headers and added lines:
109
+
110
+ ```bash
111
+ grep -n "^@@\|^+" "$DIFF_FILE" | grep -A20 "^.*+.*<relative-file-path>" | head -60
112
+ ```
113
+
114
+ If the finding's `line` number does not correspond to a `+` line in the diff
115
+ for that file, the finding is NOT commentable -- fold it into the review body
116
+ under an "Additional findings" section instead.
117
+
118
+ Observation and Idiomatic findings go into the body only; never as inline
119
+ comments.
120
+
121
+ ---
122
+
123
+ ## Step 3 -- POST the review
124
+
125
+ ```bash
126
+ gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews" \
127
+ --method POST \
128
+ --input /tmp/lekker-post-$$.json
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Step 4 -- Handle 422 errors
134
+
135
+ If the API returns HTTP 422 (line not in diff):
136
+
137
+ 1. Remove the offending comment object from the payload (identify it from the
138
+ error response body, which names the path and line).
139
+ 2. Add its content to the review-level `body` under "Additional findings".
140
+ 3. Retry the POST once with the updated payload.
141
+
142
+ If the same failure shape occurs a second time: stop, report the error message
143
+ to the user, and fall back to "paste manually" -- do not loop further.
144
+
145
+ ---
146
+
147
+ ## Step 5 -- Verify (fresh post-condition)
148
+
149
+ After a successful POST, immediately fetch the current review list:
150
+
151
+ ```bash
152
+ gh api "repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews"
153
+ ```
154
+
155
+ Confirm:
156
+ - A review with `state: "PENDING"` by the current authenticated user exists.
157
+ - The `body` field contains the expected summary text.
158
+ - The comment count matches what was submitted.
159
+
160
+ Print the following to the terminal:
161
+
162
+ ```
163
+ Posted PENDING review on <PR_URL>
164
+ - <N> inline comments
165
+ - Review ID: <id>
166
+
167
+ ACTION REQUIRED: Open GitHub in your browser to review and submit the
168
+ pending review. Pending reviews are only visible to you until submitted.
169
+ ```
170
+
171
+ Clean up the temporary payload file:
172
+
173
+ ```bash
174
+ rm -f /tmp/lekker-post-$$.json
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Step 6 -- Revising an already-posted PENDING review
180
+
181
+ If the user asks to shorten, reword, or re-scope the comments after posting:
182
+
183
+ - The review-level `body` alone can be edited in place:
184
+ `gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method PUT --input <json with {"body": ...}>`
185
+ Inline comments survive this untouched.
186
+ - **Inline comment bodies cannot be reliably edited on a pending review** --
187
+ `PATCH /pulls/comments/{id}` targets submitted comments. To change them,
188
+ DELETE the pending review and POST a fresh one:
189
+ `gh api repos/<REPO_SLUG>/pulls/<PR_NUMBER>/reviews/<REVIEW_ID> --method DELETE`
190
+ This is safe only because a pending review is visible to nobody else. Capture
191
+ the existing bodies first (`--jq '.body'` and `/reviews/<id>/comments`) so
192
+ nothing is lost if the re-POST fails.
193
+ - Verify by re-fetching the pending review and its comment count. Note that
194
+ `line`, `original_line`, and `side` come back `null` for comments on a pending
195
+ review -- that is expected, not a lost anchor. A successful POST (no 422) is
196
+ the receipt that the anchors were accepted.
197
+
198
+ ---
199
+
200
+ ## Notes
201
+
202
+ - Never add an `event` field to the payload (not even `"COMMENT"`) -- that
203
+ would publish the review immediately to all participants.
204
+ - The current authenticated user is whoever `gh auth status` reports.
205
+ - If `gh api` is not authenticated, stop and tell the user to run `gh auth login`.
@@ -0,0 +1,76 @@
1
+ # House rules (customize for your org)
2
+
3
+ This file is a template. lekker-review reads it as `PROJECT_RULES` and feeds
4
+ it to every review agent. Replace the example rules below with your own
5
+ team's non-negotiable conventions — the kind of thing that should always be a
6
+ **Critical** finding regardless of review depth, not a matter of taste.
7
+
8
+ A hard rule in this file should be:
9
+ - **Unambiguous** — a reviewer agent can check it mechanically against a diff.
10
+ - **Non-negotiable** — violating it is always wrong, not "usually" wrong.
11
+ - **Cheap to verify** — the review agent shouldn't need deep domain judgment.
12
+
13
+ If you have no hard rules yet, leave this file mostly empty (just the Stack
14
+ context section below) and let the 5 specialist agents rely on their own
15
+ judgment plus the repo's own CLAUDE.md / linter config.
16
+
17
+ ---
18
+
19
+ ## Example hard rules (replace with your own)
20
+
21
+ ### EXAMPLE-1 — Type safety (TypeScript projects)
22
+ - No type casts (`as X`, `<X>expr`) outside test files.
23
+ - No `any` outside test files; even in tests, a blatantly untyped `any[]` on a
24
+ known-shaped list should still be flagged.
25
+
26
+ ### EXAMPLE-2 — No generated files hand-edited
27
+ - Files under a `generated/` directory (codegen output, ORM types, GraphQL
28
+ types) must never be hand-edited in a diff — they should be regenerated
29
+ from source and the regen step re-run.
30
+
31
+ ### EXAMPLE-3 — Pagination must be complete
32
+ - Any paginated API call (GraphQL `nodes` connections, REST cursor pagination)
33
+ must fetch every page, not just the first, unless a comment explains why a
34
+ partial fetch is intentional.
35
+
36
+ ### EXAMPLE-4 — PR title must reference its ticket
37
+ - PR title must start with the ticket ID in brackets (e.g. `[PROJ-123]`),
38
+ covering every ticket referenced in the PR's commit history.
39
+ - Treat a missing/incomplete prefix as **blocking**: surface a prominent
40
+ `⛔ CANNOT MERGE` warning and the recommended title. This is a process rule,
41
+ not a code-quality signal, so it should not affect a confidence score.
42
+
43
+ ---
44
+
45
+ ## Repo placement check (multi-repo projects only)
46
+
47
+ If your org splits related concerns across sibling repos (e.g. a "backend
48
+ sync" repo and a separate "storefront/app" repo), add your own repo taxonomy
49
+ table here so the review agent can flag code landing in the wrong repo:
50
+
51
+ ```
52
+ | Repo pattern | Purpose |
53
+ |--------------------|-----------------------------------------|
54
+ | `<pattern-a>` | <what belongs here> |
55
+ | `<pattern-b>` | <what belongs here> |
56
+ ```
57
+
58
+ Note any exceptions (a repo that looks like pattern A but is actually a full
59
+ app, a legacy folder that shouldn't be used for new code, etc.) — placement
60
+ checks are only useful when they account for the real exceptions in your repo
61
+ layout, not the naming convention alone.
62
+
63
+ ---
64
+
65
+ ## Stack context (fill in for your project)
66
+
67
+ Give the review agents a one-paragraph map of your stack so they don't have
68
+ to rediscover it from the diff every time:
69
+
70
+ - **Backend:** <languages, frameworks, ORM, database>
71
+ - **Frontend:** <framework, UI library, build tool>
72
+ - **External APIs:** <third-party integrations worth knowing about, especially
73
+ ones with quirks: rate limits, OAuth flows, unusual pagination>
74
+ - **Infra:** <how the app runs locally and in CI>
75
+ - **Type/codegen pipeline:** <any source → generated-type steps that need to
76
+ stay in sync — flag stale generated output as a finding>