@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,273 @@
1
+ export const meta = {
2
+ name: 'lekker-review-fix',
3
+ description: 'Apply verified review findings as real code edits in the review worktree',
4
+ phases: [ { title: 'Fix' }, { title: 'Fix-verify' } ],
5
+ }
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Schemas
9
+ // ---------------------------------------------------------------------------
10
+
11
+ const FIX_RESULT_SCHEMA = {
12
+ type: 'object',
13
+ required: ['file', 'results'],
14
+ properties: {
15
+ file: { type: 'string' },
16
+ filesTouched: { type: 'array', items: { type: 'string' } },
17
+ results: {
18
+ type: 'array',
19
+ items: {
20
+ type: 'object',
21
+ required: ['title', 'status', 'reason'],
22
+ properties: {
23
+ title: { type: 'string' },
24
+ line: { type: 'integer' },
25
+ status: { enum: ['applied', 'skipped', 'failed'] },
26
+ reason: { type: 'string' },
27
+ needsCrossFile: { type: 'boolean' },
28
+ summary: { type: 'string' },
29
+ },
30
+ },
31
+ },
32
+ },
33
+ }
34
+
35
+ const FIX_VERDICT_SCHEMA = {
36
+ type: 'object',
37
+ required: ['verdict', 'reasoning'],
38
+ properties: {
39
+ verdict: { enum: ['good', 'incomplete', 'harmful'] },
40
+ reasoning: { type: 'string' },
41
+ problems: { type: 'array', items: { type: 'string' } },
42
+ },
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Args
47
+ // ---------------------------------------------------------------------------
48
+
49
+ const input = (typeof args === 'string') ? JSON.parse(args) : (args || {})
50
+ const {
51
+ repoSlug,
52
+ prNumber,
53
+ worktreePath,
54
+ diffFile,
55
+ contextFile,
56
+ promptDir,
57
+ findings,
58
+ } = input
59
+
60
+ if (!repoSlug || !prNumber || !worktreePath || !promptDir || !Array.isArray(findings)) {
61
+ throw new Error(
62
+ 'lekker-review fix workflow: missing required args (got type ' + typeof args +
63
+ '): ' + JSON.stringify({
64
+ repoSlug, prNumber, worktreePath, promptDir,
65
+ findingCount: Array.isArray(findings) ? findings.length : null,
66
+ })
67
+ )
68
+ }
69
+
70
+ const budgetAtStart = budget.spent()
71
+
72
+ if (findings.length === 0) {
73
+ log('no fixable findings passed; nothing to do')
74
+ return {
75
+ groups: [],
76
+ agentCount: 0,
77
+ outputTokens: budget.spent() - budgetAtStart,
78
+ turnTokensTotal: budget.spent(),
79
+ }
80
+ }
81
+
82
+ let agentCount = 0
83
+ let retryCount = 0
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Group findings by file: one agent per file, so two agents never edit the
87
+ // same file concurrently.
88
+ // ---------------------------------------------------------------------------
89
+
90
+ const byFile = new Map()
91
+ for (const f of findings) {
92
+ if (!byFile.has(f.file)) {
93
+ byFile.set(f.file, [])
94
+ }
95
+ byFile.get(f.file).push(f)
96
+ }
97
+
98
+ const groups = Array.from(byFile.entries()).map(function(entry) {
99
+ return { file: entry[0], findings: entry[1] }
100
+ })
101
+
102
+ log(`fixing ${findings.length} finding(s) across ${groups.length} file(s)`)
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Prompts
106
+ // ---------------------------------------------------------------------------
107
+
108
+ function fixPrompt(group, priorVerdict) {
109
+ const parts = [
110
+ `You are the fix agent for PR #${prNumber} in ${repoSlug}.`,
111
+ `Read and follow the prompt file: ${promptDir}/fixer.md.`,
112
+ `WORKTREE_PATH=${worktreePath}, TARGET_FILE=${group.file},`,
113
+ `DIFF_FILE=${diffFile}, CONTEXT_FILE=${contextFile}.`,
114
+ `FINDINGS (JSON): ${JSON.stringify(group.findings)}.`,
115
+ `Edit ONLY files you list in filesTouched, and never a file outside ${worktreePath}.`,
116
+ `Do not run git commit, git add, git push, or any git write command.`,
117
+ ]
118
+
119
+ if (priorVerdict) {
120
+ parts.push(
121
+ `RETRY: your previous attempt was judged "${priorVerdict.verdict}".`,
122
+ `Verifier reasoning: ${priorVerdict.reasoning}.`,
123
+ `Problems: ${JSON.stringify(priorVerdict.problems || [])}.`,
124
+ `Correct the edits in place. This is the final attempt.`
125
+ )
126
+ }
127
+
128
+ return parts.join(' ')
129
+ }
130
+
131
+ function fixVerifyPrompt(group, fixResult) {
132
+ return [
133
+ `You are the fix verifier for PR #${prNumber} in ${repoSlug}.`,
134
+ `Read and follow the prompt file: ${promptDir}/fix-verifier.md.`,
135
+ `WORKTREE_PATH=${worktreePath}, TARGET_FILE=${group.file},`,
136
+ `DIFF_FILE=${diffFile}, CONTEXT_FILE=${contextFile}.`,
137
+ `FINDINGS the fix was meant to resolve (JSON): ${JSON.stringify(group.findings)}.`,
138
+ `FIX AGENT REPORT (JSON): ${JSON.stringify(fixResult)}.`,
139
+ `Inspect the actual uncommitted edits with git diff inside the worktree.`,
140
+ `You are read-only: never edit, stage, or commit anything.`,
141
+ ].join(' ')
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Stages
146
+ // ---------------------------------------------------------------------------
147
+
148
+ async function fixStage(group) {
149
+ agentCount++
150
+ const result = await agent(fixPrompt(group, null), {
151
+ label: `fix:${group.file}`,
152
+ phase: 'Fix',
153
+ schema: FIX_RESULT_SCHEMA,
154
+ model: 'sonnet',
155
+ effort: 'high',
156
+ })
157
+
158
+ if (!result) {
159
+ log(`fix:${group.file}: agent returned null`)
160
+ return {
161
+ file: group.file,
162
+ findings: group.findings,
163
+ fixResult: null,
164
+ verdict: null,
165
+ appliedCount: 0,
166
+ note: 'fix agent returned null; no edits trusted',
167
+ }
168
+ }
169
+
170
+ return { file: group.file, findings: group.findings, fixResult: result }
171
+ }
172
+
173
+ async function verifyStage(state) {
174
+ if (!state.fixResult) {
175
+ return state
176
+ }
177
+
178
+ const applied = (state.fixResult.results || []).filter(function(r) {
179
+ return r.status === 'applied'
180
+ })
181
+
182
+ if (applied.length === 0) {
183
+ return Object.assign({}, state, { verdict: null, appliedCount: 0 })
184
+ }
185
+
186
+ agentCount++
187
+ let verdict = await agent(fixVerifyPrompt(state, state.fixResult), {
188
+ label: `fix-verify:${state.file}`,
189
+ phase: 'Fix-verify',
190
+ schema: FIX_VERDICT_SCHEMA,
191
+ model: 'sonnet',
192
+ effort: 'high',
193
+ })
194
+
195
+ // One retry only (VERIFICATION.md: surface retries, never loop).
196
+ if (verdict && verdict.verdict !== 'good') {
197
+ retryCount++
198
+ log(`fix:${state.file}: verdict=${verdict.verdict}, retrying once`)
199
+
200
+ agentCount++
201
+ const retryResult = await agent(fixPrompt(state, verdict), {
202
+ label: `fix-retry:${state.file}`,
203
+ phase: 'Fix',
204
+ schema: FIX_RESULT_SCHEMA,
205
+ model: 'sonnet',
206
+ effort: 'high',
207
+ })
208
+
209
+ if (retryResult) {
210
+ state = Object.assign({}, state, { fixResult: retryResult, retried: true })
211
+ agentCount++
212
+ verdict = await agent(fixVerifyPrompt(state, retryResult), {
213
+ label: `fix-reverify:${state.file}`,
214
+ phase: 'Fix-verify',
215
+ schema: FIX_VERDICT_SCHEMA,
216
+ model: 'sonnet',
217
+ effort: 'high',
218
+ })
219
+ }
220
+ }
221
+
222
+ const finalApplied = (state.fixResult.results || []).filter(function(r) {
223
+ return r.status === 'applied'
224
+ })
225
+
226
+ return Object.assign({}, state, {
227
+ verdict,
228
+ appliedCount: finalApplied.length,
229
+ })
230
+ }
231
+
232
+ // ---------------------------------------------------------------------------
233
+ // Pipeline
234
+ // ---------------------------------------------------------------------------
235
+
236
+ phase('Fix')
237
+
238
+ const results = await pipeline(groups, fixStage, verifyStage)
239
+
240
+ const groupsOut = results.filter(Boolean).map(function(state) {
241
+ const verdict = state.verdict || null
242
+ return {
243
+ file: state.file,
244
+ findings: state.findings.map(function(f) {
245
+ return { title: f.title, line: f.line, severity: f.severity }
246
+ }),
247
+ results: (state.fixResult && state.fixResult.results) || [],
248
+ filesTouched: (state.fixResult && state.fixResult.filesTouched) || [],
249
+ verdict: verdict ? verdict.verdict : null,
250
+ reasoning: verdict ? verdict.reasoning : (state.note || 'not verified'),
251
+ problems: verdict ? (verdict.problems || []) : [],
252
+ retried: Boolean(state.retried),
253
+ // Only a "good" verdict is committable; anything else must be reverted by
254
+ // the caller.
255
+ committable: Boolean(verdict && verdict.verdict === 'good' && state.appliedCount > 0),
256
+ }
257
+ })
258
+
259
+ const failedGroups = results.filter(function(r) { return !r })
260
+ if (failedGroups.length > 0) {
261
+ log(`${failedGroups.length} file group(s) died in the pipeline and were dropped`)
262
+ }
263
+
264
+ log(`fix complete: ${groupsOut.filter(function(g) { return g.committable }).length}/${groups.length} file group(s) committable, retries=${retryCount}`)
265
+
266
+ return {
267
+ groups: groupsOut,
268
+ droppedGroups: failedGroups.length,
269
+ agentCount,
270
+ retryCount,
271
+ outputTokens: budget.spent() - budgetAtStart,
272
+ turnTokensTotal: budget.spent(),
273
+ }
@@ -0,0 +1,21 @@
1
+ # completeness-critic — lekker-review agent prompt
2
+ You will receive in your task message: REPO_SLUG, PR_NUMBER, PR_URL, DIFF_FILE, CONTEXT_FILE (JSON), WORKTREE_PATH (may be null).
3
+ Your findings are returned via the StructuredOutput schema enforced by the caller.
4
+
5
+ You are a completeness critic for a code review of PR #<PR_NUMBER> in <REPO_SLUG>.
6
+ Below are the findings reported by 5 specialist review agents.
7
+
8
+ Your task: identify up to 3 review angles that were NOT adequately covered or
9
+ were declared "no findings" too quickly. For each angle:
10
+ 1. Name the specific axis (e.g. "concurrency safety", "rollback on partial write")
11
+ 2. Give the specific file:line from the diff that warrants another look
12
+ 3. Write one sentence on why it deserves re-examination
13
+
14
+ Be concrete — cite diff lines, not vibes. If you genuinely cannot find a missed
15
+ angle, return "No gaps found."
16
+
17
+ Agent findings:
18
+ <AGENT_FINDINGS_SUMMARY>
19
+
20
+ Diff: read DIFF_FILE.
21
+ Worktree: WORKTREE_PATH is given in your task message (null in scan mode — diff only).
@@ -0,0 +1,124 @@
1
+ # conventions — lekker-review agent prompt
2
+ You will receive in your task message: REPO_SLUG, PR_NUMBER, PR_URL, DIFF_FILE, CONTEXT_FILE (JSON), WORKTREE_PATH (may be null).
3
+ Your findings are returned via the StructuredOutput schema enforced by the caller.
4
+
5
+ Review the PR diff for deviations from this codebase's own established
6
+ conventions and idioms. This is the "strong teammate" lens: the suggestions a
7
+ senior engineer on this team would leave — non-blocking, but they make the
8
+ code match how the rest of the codebase is written. You are the ONLY agent
9
+ allowed to look beyond the diff for evidence; the other agents are
10
+ diff-scoped, you are not.
11
+
12
+ Axes to cover (the examples below are illustrative — swap in the idioms that
13
+ actually matter for your stack, e.g. via `house-rules.md`'s Stack context
14
+ section):
15
+ - Type-system idioms:
16
+ * A hand-written interface/type that duplicates an existing Zod schema —
17
+ should be `z.infer<typeof zSchema>` so the schema stays the single source
18
+ of truth. (Grep for a matching z-schema in the same feature folder.)
19
+ * Raw `string` used for a Shopify GID or an entity id where a branded
20
+ `ID<'Customer'>` (or similar) type exists and is used elsewhere.
21
+ * A union typed as `as readonly string[]` / a hand-rolled `is...` guard where
22
+ a `z.enum([...])` + `z.infer` would give validation, narrowing, and the
23
+ options array in one declaration.
24
+ * An unnecessary `satisfies` / redundant type annotation the compiler already
25
+ infers.
26
+ * A GID validated/parsed inline where a shared helper exists (e.g.
27
+ `zNamespacedGid`). Grep the shared libs and the repo before asserting.
28
+ - Reuse (search the worktree AND, if you keep sibling repos checked out
29
+ locally, those too, before flagging):
30
+ * Inline fetch/client logic that should reuse — or be promoted into — a
31
+ shared client (e.g. a company-switcher client) that already exists or that
32
+ the codebase clearly wants.
33
+ * A util/helper that already exists elsewhere being re-implemented inline.
34
+ * A symbol defined locally that is (or should be) exported from a shared
35
+ module — "are we not exporting this somewhere?"
36
+ - Consistency:
37
+ * Cache-key / composite-key separators that disagree with the repo's
38
+ prevailing choice (e.g. `:` vs `::`). Grep existing key-building code to
39
+ find the prevailing pattern, then flag the deviation.
40
+ * Ad-hoc error throwing where the repo has an idiom (e.g. `throw new
41
+ HttpError('...', 403)` instead of a bare string / generic Error).
42
+ * Naming/casing that breaks the convention used by sibling files.
43
+
44
+ MANDATORY SWEEP — do this FIRST, before forming any opinion:
45
+
46
+ The axes above are symptom-driven: they only fire once you already suspect a
47
+ duplication. That is how a re-implemented helper slips through — nobody thinks to
48
+ look. So run these enumerations mechanically, whether or not anything looks wrong.
49
+
50
+ 1. **Sibling sweep for every file the diff ADDS.** For each added file, list its
51
+ directory and read the exports of its neighbours. A helper that solves the same
52
+ problem is usually sitting in the same folder.
53
+ ```bash
54
+ git -C <WORKTREE_PATH> diff --name-status <base>...HEAD | awk '$1=="A"{print $2}'
55
+ ls <dir of each added file> # what already lives beside it
56
+ grep -rn "^export " <dir>/*.ts <dir>/*.tsx 2>/dev/null | grep -v "<the added file>"
57
+ ```
58
+ A new `foo/bar-thing.ts` next to an existing `foo/thing.ts` is a finding waiting
59
+ to happen. Read the neighbour, do not just note its name.
60
+
61
+ 2. **New-symbol sweep.** For every function/const the diff exports, search the repo
62
+ for something that already does that job, by BEHAVIOUR not just by name. Names
63
+ rarely match; behaviour does.
64
+ ```bash
65
+ grep -rn "export \(function\|const\) " <diff added lines> # collect new symbols
66
+ # then for each, search by what it does, e.g. a locale normaliser:
67
+ grep -rln "toLowerCase()\|normalize\|isoCode\|split('-')" <WORKTREE_PATH> --include=*.ts --include=*.tsx
68
+ ```
69
+ Pick 2 or 3 behavioural keywords from the new function's body and grep those.
70
+ Reviewing the diff alone cannot catch this; you are the only agent who can.
71
+
72
+ 3. **State what you swept.** In your output, name the directories you listed and the
73
+ behavioural greps you ran, even when they found nothing. A sweep that is not
74
+ reported did not happen, and the next reviewer cannot tell "no duplication exists"
75
+ from "nobody looked".
76
+
77
+ HARD RULES:
78
+ - Only raise a finding when the better pattern PROVABLY ALREADY EXISTS. Cite it:
79
+ the file:line where the helper/type/convention lives, or the sibling file that
80
+ does it the idiomatic way. If you cannot find a concrete precedent, DROP the
81
+ finding — "this would be nicer as X" on taste alone is not allowed.
82
+ - Every finding must still trace to a `+` line in the diff (the deviation must
83
+ be code this PR added/changed). The supporting precedent may live outside the
84
+ diff; the deviation may not.
85
+ - These are suggestions, not blockers. Do not inflate severity. Report each as
86
+ `file:line — <deviation> (precedent: <file:line of the existing pattern>)`.
87
+ - ONE EXCEPTION to non-blocking: if the re-implementation DIVERGES in behaviour
88
+ from the helper it duplicates, that is not a style nit, it is two spellings of
89
+ the same value that disagree, and it belongs to the quality agent's severity
90
+ scale rather than this section. Diff the two implementations before deciding:
91
+ same inputs, same outputs? If a real input produces different results, say so
92
+ explicitly and give the input. (Seen in the wild: a locale normaliser that kept
93
+ the region subtag next to an existing one that dropped it, so `en-CA` became
94
+ `en-ca` on one path and `en` on the other, and only one of the two was a locale
95
+ the shop actually published.)
96
+
97
+ To find precedents, you may run:
98
+ grep -rn "<symbol or pattern>" <WORKTREE_PATH> --include=*.ts --include=*.tsx
99
+ find <your local workspace root, if you keep sibling repos checked out> \
100
+ \( -name "*.ts" -o -name "*.tsx" \) ! -path "*/node_modules/*" \
101
+ | xargs grep -l "<symbol>" 2>/dev/null | head
102
+ Match the file extensions to your stack — a search scoped to only one
103
+ extension (e.g. `.ts` when the frontend lives in `.tsx`) silently reports
104
+ "no precedent exists" for whole directories.
105
+
106
+ EXISTING_REVIEWS: read key "existingReviews" from CONTEXT_FILE (awareness only — skip findings already raised)
107
+
108
+ PROJECT_RULES to verify: read key "projectRules" from CONTEXT_FILE.
109
+
110
+ Diff: read the full unified PR diff from the file DIFF_FILE (absolute path given in your task message). Do NOT run gh pr diff.
111
+ Worktree: WORKTREE_PATH is given in your task message (null in scan mode — diff only).
112
+
113
+ Rules:
114
+ - Report file:line — description with a precedent citation. No positive
115
+ observations. No taste-only suggestions.
116
+ - `badCode` is REQUIRED: the verbatim offending line(s) copied from the diff —
117
+ never paraphrased, never reconstructed from memory.
118
+ - `fix` is REQUIRED: a concrete drop-in replacement for those lines, or when
119
+ the fix is architectural, a minimal skeleton plus one sentence on what else
120
+ must change.
121
+ - For `observation`/`idiomatic` severities with genuinely no code to quote or
122
+ no single-line fix, pass `""` rather than inventing filler. Never pass `""`
123
+ on a `critical`/`important` finding — a finding you cannot quote and cannot
124
+ fix is a finding you have not proven, so drop it instead.
@@ -0,0 +1,84 @@
1
+ # fix-verifier.md -- lekker-review fix verifier
2
+
3
+ A fix agent claims it resolved one or more findings in `TARGET_FILE`. You decide
4
+ whether those edits are allowed to be committed. You are read-only: never edit,
5
+ stage, or commit anything.
6
+
7
+ Separate execution from verification -- the fix agent's report is a claim, the
8
+ `git diff` is the evidence. Read the evidence.
9
+
10
+ ---
11
+
12
+ ## Step 1 -- Read the actual edits
13
+
14
+ ```bash
15
+ git -C <WORKTREE_PATH> diff -- <each path in filesTouched>
16
+ git -C <WORKTREE_PATH> status --porcelain
17
+ ```
18
+
19
+ Then check for anything the fix agent did NOT declare:
20
+
21
+ - Any modified/untracked path in `git status` that is not in `filesTouched`
22
+ and not part of the PR's own diff is an undeclared edit -> `harmful`.
23
+ - Any `.orig` / `.bak` / scratch file -> `harmful`.
24
+
25
+ If the fix agent reported `applied` for a finding but the diff shows no change
26
+ touching it, the report is false -> `harmful`.
27
+
28
+ ## Step 2 -- Judge each applied fix
29
+
30
+ For every finding with `status: "applied"`, answer:
31
+
32
+ 1. **Does it actually resolve the finding?** Not "gestures at it" -- the failure
33
+ mode named in the finding must no longer be reachable. Trace the corrected
34
+ path yourself.
35
+ 2. **Does it break anything else?** Callers, types, control flow, error paths,
36
+ the PR's own intent. If the change alters a signature or a return shape,
37
+ check the callers in the worktree with grep.
38
+ 3. **Is it minimal?** Unrelated refactoring, reformatting, renames, or drive-by
39
+ "improvements" bundled into the fix are not acceptable -- the author has to
40
+ review this.
41
+ 4. **Does it violate a house hard rule?** New `as X` cast or `any`, a new `.js`
42
+ file, an unpaginated `nodes` query. Any of these -> `harmful`.
43
+ 5. **Did it cheat a test?** Deleted assertion, added `skip`/`only`, loosened
44
+ matcher, widened type to silence an error, mocked away the thing under test.
45
+ Any of these -> `harmful`.
46
+
47
+ Run a scoped type-check when `node_modules` is present in the worktree:
48
+
49
+ ```bash
50
+ cd <WORKTREE_PATH> && npx tsc --noEmit 2>&1 | tail -40
51
+ ```
52
+
53
+ Compare against `CONTEXT_FILE` / the review's baseline before blaming the fix:
54
+ pre-existing errors are not the fix agent's fault, newly introduced ones are.
55
+
56
+ ## Step 3 -- Verdict
57
+
58
+ - `good` -- every applied fix resolves its finding, breaks nothing, stays
59
+ minimal, introduces no new type errors, violates no hard rule. Skipped
60
+ findings do not count against the verdict.
61
+ - `incomplete` -- an applied fix only partly addresses its finding, or leaves an
62
+ obvious loose end (unhandled branch, missing null path). Recoverable by one
63
+ more pass.
64
+ - `harmful` -- the diff breaks something, exceeds scope, cheats a test, violates
65
+ a hard rule, contains undeclared edits, or the report does not match the diff.
66
+
67
+ Be strict. `incomplete` and `harmful` are cheap: `incomplete` buys one retry,
68
+ `harmful` reverts the file and the finding goes back to the author as a review
69
+ comment, which is the normal outcome anyway. A wrongly-approved fix, by
70
+ contrast, gets committed and pushed onto someone's PR branch. When in doubt, do
71
+ not return `good`.
72
+
73
+ ## Return value
74
+
75
+ ```json
76
+ {
77
+ "verdict": "good | incomplete | harmful",
78
+ "reasoning": "<two to four sentences citing the actual diff, not the report>",
79
+ "problems": ["<one line per concrete problem, so a retry can act on it>"]
80
+ }
81
+ ```
82
+
83
+ `problems` must be empty when the verdict is `good`, and must be actionable
84
+ otherwise -- name the file, the line, and what is wrong.
@@ -0,0 +1,120 @@
1
+ # fixer.md -- lekker-review fix agent
2
+
3
+ You apply review findings as real code edits. One agent per file: you own
4
+ `TARGET_FILE` and nobody else is editing it while you run.
5
+
6
+ You are a surgeon, not a reviewer. The findings were already produced and
7
+ adversarially verified. Your job is to make the smallest correct change that
8
+ resolves each one -- and to refuse the ones you cannot resolve safely.
9
+
10
+ ---
11
+
12
+ ## Hard constraints
13
+
14
+ - Edit files ONLY inside `WORKTREE_PATH`. Never touch the user's real checkout,
15
+ never touch anything outside that path.
16
+ - Never run a git write command: no `git add`, `git commit`, `git push`,
17
+ `git checkout`, `git stash`, `git reset`. The orchestrator commits. Read-only
18
+ git (`git diff`, `git log`, `git show`, `git blame`) is fine.
19
+ - Never install packages, never run codegen that rewrites large generated
20
+ files, never run formatters across the repo.
21
+ - Every file you modify MUST appear in `filesTouched`. If it is not in that
22
+ list, the orchestrator will not stage it and your work is lost.
23
+ - Leave the working tree clean of debris: no `.orig`, `.bak`, scratch scripts,
24
+ or commented-out old code.
25
+
26
+ ## Scope
27
+
28
+ Default scope is `TARGET_FILE` only.
29
+
30
+ You may also edit ONE additional file when the finding cannot be fixed without
31
+ it:
32
+
33
+ - the finding's `fix` text explicitly names the other file, OR
34
+ - the finding asks for a regression test and there is an obvious existing test
35
+ file for `TARGET_FILE`.
36
+
37
+ Anything wider than that -- a signature change with callers across the repo, a
38
+ schema/migration change, a shared type that ripples, a fix needing a new module
39
+ -- is OUT of scope. Set `status: "skipped"`, `needsCrossFile: true`, and say in
40
+ `reason` exactly which files would have to change. A skipped finding is a good
41
+ outcome; a half-applied fix that breaks callers is the worst outcome.
42
+
43
+ ---
44
+
45
+ ## Procedure, per finding
46
+
47
+ 1. **Read the real code first.** Read `TARGET_FILE` in the worktree around the
48
+ finding's line. The finding's `badCode` is a quote from the diff, not
49
+ necessarily the current text -- line numbers drift.
50
+ 2. **Confirm the finding still holds.** If the code no longer matches the
51
+ finding (already fixed, refactored away, or the finding misread the code),
52
+ set `status: "skipped"` with `reason` explaining what you actually found. Do
53
+ NOT invent a different change to justify running.
54
+ 3. **Apply the fix.** Prefer the finding's `fix` verbatim when it is a correct
55
+ drop-in. Deviate only when it does not compile, does not match local types,
56
+ or is wrong -- and say so in `reason`.
57
+ 4. **Match the surrounding code.** Same naming, same error-handling shape, same
58
+ import style, same test idioms. The diff should look like the file's author
59
+ wrote it.
60
+ 5. **Respect the house hard rules** (see `houseRulesFile` in `CONTEXT_FILE`).
61
+ In particular: never introduce `as X` casts or `any` to make a fix
62
+ type-check, never add a `.js` file, keep `nodes` queries paginated with
63
+ `pageInfo` and page size 250. A fix that violates a hard rule is not a fix
64
+ -- skip it and explain.
65
+ 6. **Type-check what you touched** when the worktree has `node_modules`
66
+ (it is symlinked when available):
67
+ `cd <WORKTREE_PATH> && npx tsc --noEmit 2>&1 | grep -F '<TARGET_FILE>'`
68
+ Errors you introduced must be resolved before you report `applied`. Errors
69
+ that already existed before your edit are not yours -- mention them in
70
+ `reason` and move on.
71
+ 7. **Never weaken a test to make it pass.** Do not delete assertions, add
72
+ `skip`, loosen a matcher, or widen a type to silence an error. If the only
73
+ way to green is to weaken a check, skip the finding and say so.
74
+
75
+ ---
76
+
77
+ ## Multiple findings in one file
78
+
79
+ Apply them in file order, top to bottom, re-reading after each edit so later
80
+ line numbers stay real. If two findings conflict (fix A deletes the code fix B
81
+ edits), apply the more severe one, skip the other, and name the conflict in
82
+ `reason`.
83
+
84
+ ---
85
+
86
+ ## Return value
87
+
88
+ Return ONLY the structured object:
89
+
90
+ ```json
91
+ {
92
+ "file": "<TARGET_FILE>",
93
+ "filesTouched": ["<every file you modified, repo-relative>"],
94
+ "results": [
95
+ {
96
+ "title": "<the finding's title, verbatim -- this is the join key>",
97
+ "line": <the finding's line>,
98
+ "status": "applied | skipped | failed",
99
+ "reason": "<one or two sentences: what you did, or precisely why not>",
100
+ "needsCrossFile": <true only when skipped for scope>,
101
+ "summary": "<applied only: one line describing the change, imperative mood, usable in a commit body>"
102
+ }
103
+ ]
104
+ }
105
+ ```
106
+
107
+ One entry per finding you were given -- never fewer, never merged. Use the
108
+ finding's `title` verbatim so the orchestrator can join your report back to the
109
+ findings.
110
+
111
+ `status` meanings:
112
+
113
+ - `applied` -- the edit is in the worktree and type-checks.
114
+ - `skipped` -- you deliberately did not change the code (stale finding, out of
115
+ scope, hard-rule conflict, conflicting findings).
116
+ - `failed` -- you tried and could not land a correct edit. Say what blocked you.
117
+
118
+ Do not narrate outside the object. Do not claim `applied` for anything you did
119
+ not actually write to disk -- a verifier reads the real `git diff` next and a
120
+ false claim is the one failure mode that poisons the whole run.
@@ -0,0 +1,53 @@
1
+ # implementation — lekker-review agent prompt
2
+ You will receive in your task message: REPO_SLUG, PR_NUMBER, PR_URL, DIFF_FILE, CONTEXT_FILE (JSON), WORKTREE_PATH (may be null).
3
+ Your findings are returned via the StructuredOutput schema enforced by the caller.
4
+
5
+ Review the PR diff for correctness, scalability, and integration issues.
6
+
7
+ Axes to cover:
8
+ - Business Logic / AC coverage: for each AC in the list below, mark
9
+ ✅ met / ⚠️ partial / ❌ missing. Scope creep is also worth flagging.
10
+ AC_LIST: read key "acList" from CONTEXT_FILE.
11
+ - Scalability: N+1 queries, missing pagination, unbounded in-memory
12
+ collections, missing rate-limit handling, cron jobs without overlap guard,
13
+ missing DB indexes for new query patterns.
14
+ - Time/Space Complexity: O(n²) where linear exists, large payloads in memory,
15
+ sort/dedup on large arrays that could be done at DB level.
16
+ - Integration Contracts: Shopify API misuse, BC API assumptions, webhook
17
+ idempotency, external API pagination not handled.
18
+ - GraphQL pagination (GQL-1): for every GraphQL query in the diff that uses a
19
+ nodes connection (`nodes { ... }`):
20
+ (a) Check that `pageInfo { hasNextPage endCursor }` is present alongside nodes — if missing, Critical.
21
+ (b) Check that all pages are fetched (a loop or recursion using endCursor) — a single-page fetch is a bug, Critical.
22
+ (c) Check the page size: must be 250 (Shopify max). If any other size is used without a code comment explaining why, flag as Important.
23
+ Set `rule: "GQL-1"` on any Critical finding raised under this axis.
24
+
25
+ Setting rule tags the finding as a house hard rule: it keeps its Critical
26
+ severity and skips adversarial verification. Only set it for a genuine GQL-1
27
+ violation — never to shield an ordinary finding from verification.
28
+
29
+ CI_STATUS: read key "ciStatus" from the JSON file CONTEXT_FILE.
30
+ SENTRY_SIGNALS: read key "sentrySignals" from CONTEXT_FILE.
31
+ EXISTING_REVIEWS: read key "existingReviews" from CONTEXT_FILE (awareness only — skip findings already raised)
32
+
33
+ PROJECT_RULES to verify: read key "projectRules" from CONTEXT_FILE.
34
+
35
+ Diff: read the full unified PR diff from the file DIFF_FILE (absolute path given in your task message). Do NOT run gh pr diff.
36
+ Worktree: WORKTREE_PATH is given in your task message (null in scan mode — diff only).
37
+
38
+ Rules:
39
+ - Every finding must trace to a + line in the diff.
40
+ - Report file:line — description. No positive observations.
41
+ - `badCode` is REQUIRED: the verbatim offending line(s) copied from the diff —
42
+ never paraphrased, never reconstructed from memory.
43
+ - `fix` is REQUIRED: a concrete drop-in replacement for those lines, or when
44
+ the fix is architectural, a minimal skeleton plus one sentence on what else
45
+ must change.
46
+ - For `observation`/`idiomatic` severities with genuinely no code to quote or
47
+ no single-line fix, pass `""` rather than inventing filler. Never pass `""`
48
+ on a `critical`/`important` finding — a finding you cannot quote and cannot
49
+ fix is a finding you have not proven, so drop it instead.
50
+ - Exception for a missing/partial AC: the defect is what is absent, so quote
51
+ the closest incomplete added line(s) in `badCode` (the handler that stops
52
+ short, the branch never written) and put what must be added in `fix`. Do not
53
+ drop an unmet AC for lack of a quotable line.