@pmelab/gtd 13.0.0 → 14.0.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.
@@ -0,0 +1,682 @@
1
+ import { head, start, vars, type SummaryContext } from "../flows/index.js"
2
+ import {
3
+ skillsPreamble,
4
+ styleBlock,
5
+ styleFormatContract,
6
+ agentConduct,
7
+ designPersona,
8
+ architectPersona,
9
+ reviewerPersona,
10
+ specReviewerPersona,
11
+ builderPersona,
12
+ finisherPersona,
13
+ escalationPersona,
14
+ stateFileRules,
15
+ questionBar,
16
+ questionBarReturn,
17
+ fixFeedbackPrompt,
18
+ footnoteRules,
19
+ footnoteFoldIn,
20
+ } from "./prose.js"
21
+
22
+ // The bundled workflow's prompts, messages and scripts. Each is evaluated
23
+ // when its step is reached, against the commit replay stands on.
24
+
25
+ /** `prompt` behind the skills preamble naming `skills`; blank skills leave it bare. */
26
+ export const withSkills = (skills: string | undefined, prompt: string): string => {
27
+ if (skills === undefined || skills.trim() === "") return prompt
28
+ return `${skillsPreamble.replaceAll("{skills}", skills)}\n\n${prompt}`
29
+ }
30
+
31
+ export const unwindFailure = (commit: string): string =>
32
+ `gtd could not unwind ${commit} out of your working tree.`
33
+
34
+ export const idleMessage = (): string =>
35
+ `No active gtd process.
36
+
37
+ To start one, make ANY change — a hand-edit to real code, a scratch
38
+ note, anything at all. .gtd/TODO.md is a good default
39
+ place to start sketching. gtd treats it as a SKETCH, not finished
40
+ work: the very next beat unwinds it out of your working tree (its
41
+ intent survives in history, for the triage phase to read), then
42
+ checks the test baseline is green, then triages the reverted diff
43
+ into ordered, classified concerns: product questions, then
44
+ technical questions, then one package per concern, built and
45
+ reviewed in parallel.
46
+
47
+ What each change does next (then run \`gtd land\`):
48
+ - **Start** — make any change — gtd unwinds it out of your working tree (its intent survives in history) before checking the test baseline is green, then triages the reverted diff into ordered, classified concerns and resolves product questions, then technical ones, before building each concern's package (**unwind** -> **start-gate.check**).
49
+ `
50
+
51
+ export const unwindFailedMessage = (): string =>
52
+ `gtd could not revert your sketch out of the working tree.
53
+ \`.gtd/FEEDBACK.md\` holds the error.
54
+
55
+ Undo the sketch by hand (its intent survives in history either
56
+ way), then continue — gtd will not start work on a tree that still
57
+ carries it.
58
+
59
+ What each change does next (then run \`gtd land\`):
60
+ - **Continue** — having undone the sketch by hand, check the test baseline is green and start triage (**start-gate.check**).
61
+ `
62
+
63
+ export const architecturePreMessage = (): string =>
64
+ `Judging whether \`.gtd/REQUIREMENTS.md\`'s settled concerns need a
65
+ dedicated architecture pass — real structural decisions, multiple
66
+ integration points, or a non-obvious tradeoff — before packages
67
+ are written. Run \`gtd judge answer\` and pipe a verdict for
68
+ \`architectureWarranted\` — or land untouched to run the full pass
69
+ (the conservative default; a skipped judgment never suppresses
70
+ it).
71
+ `
72
+
73
+ export const startGateBlockedMessage = (): string =>
74
+ `The test baseline is red — gtd will not start new work on a broken suite.
75
+ \`.gtd/FEEDBACK.md\` holds the failing output.
76
+
77
+ What each change does next (then run \`gtd land\`):
78
+ - **Retry check** — edit the code and/or \`.gtd/FEEDBACK.md\` to fix the failing tests (**start-gate.check**). To repair the baseline as its own separate reviewed commit instead, abandon this start and run \`gtd --entry fix-precheck\` from a clean \`idle\`.
79
+ `
80
+
81
+ export const reviewGateBlockedMessage = (): string =>
82
+ `The test baseline is red — gtd will not start a review on a broken suite.
83
+ \`.gtd/FEEDBACK.md\` holds the failing output.
84
+
85
+ What each change does next (then run \`gtd land\`):
86
+ - **Retry check** — edit the code and/or \`.gtd/FEEDBACK.md\` to fix the failing tests (**review-gate.check**).
87
+ `
88
+
89
+ export const designTriagePrompt = (base: string): string =>
90
+ `${styleBlock}
91
+
92
+ ${styleFormatContract}
93
+
94
+ ${stateFileRules}
95
+ ${footnoteFoldIn}
96
+ - The only state file this turn touches is \`.gtd/REQUIREMENTS.md\`
97
+ — no other files for notes or output
98
+ - \`.gtd/TODO.md\` is the likely home of the sketch that started
99
+ this process — the human's input, folded into the concerns
100
+ below like any other part of the start diff; never a state
101
+ file to preserve, never gtd bookkeeping to ignore
102
+ - This process started at commit \`${start()}\`,
103
+ reverted out of the tree by \`unwind\` right after landing, so
104
+ \`git diff ${start()}\` is now empty — its content
105
+ survives only in history. Find the entry commit yourself:
106
+ \`git rev-list --ancestry-path ${start()}..HEAD | tail -1\`
107
+ (the process's first turn, before any baseline-repair
108
+ commits), then \`git show\` it — a hand-edit, a scratch note,
109
+ or both
110
+ - Whichever lap this is, leave \`.gtd/REQUIREMENTS.md\`
111
+ uncommitted and finish once it reflects this lap's own work
112
+
113
+ ## First lap
114
+
115
+ \`.gtd/REQUIREMENTS.md\` does not exist yet (or holds whatever the
116
+ human's change left there). Build it from that start diff into an
117
+ ordered list of concerns, each classified below.
118
+
119
+ ### Classify each concern
120
+
121
+ Classify each as PRODUCT (user-facing/requirements) or TECHNICAL
122
+ (implementation).
123
+
124
+ ${questionBar}
125
+
126
+ Raise questions only for product concerns here — technical ones
127
+ wait for the next phase. When every concern is TECHNICAL, write
128
+ no \`## Open Questions\` section. STRICT: answer it yourself only
129
+ when the product default is unmistakable; a wrong intent costs a
130
+ whole rebuild lap.
131
+
132
+ ### Fold in the sketch
133
+
134
+ - Fold everything the entry commit added under the concern it
135
+ belongs to — a scratch note and a real code edit are both
136
+ just a sketch to finish, never work to preserve; \`unwind\`
137
+ already reverted both, so there is nothing left to delete
138
+
139
+ ## Return lap
140
+
141
+ ${questionBarReturn}
142
+ ## Review loop-back
143
+
144
+ - \`.gtd/REQUIREMENTS.md\` already holds concerns with no
145
+ ticked-but-unfolded answer waiting — a completed REVIEW round
146
+ put this here, not a question you asked. Develop those
147
+ concerns further with whatever the round raised; never
148
+ rediscover or regroup them cold, the way the first lap does
149
+ - The human's review-round edit was reverted the same way the
150
+ entry commit was — read it from history:
151
+ \`git show ${base}\`. (On the first lap that hash
152
+ is the process's own diff base, \`${start()}\` — this
153
+ branch doesn't apply)
154
+ - Every decision under \`## Answered Questions\` stays settled —
155
+ never re-open one. A genuinely open PRODUCT point may still
156
+ raise a fresh \`## Open Questions\` entry: the product gate sits
157
+ on this path exactly as on the first lap
158
+ - Before grouping anything, run \`${vars.testCommand}\`
159
+ yourself — a loop-back runs no green-baseline gate, so the
160
+ tree may already be red (reverting the edit can undo a fix it
161
+ made). If red, make that breakage the first concern, ahead of
162
+ everything else — every later concern's green-on-its-own
163
+ property assumes the suite started green
164
+ `
165
+
166
+ export const designSystem = (): string =>
167
+ `${designPersona}
168
+
169
+ ${agentConduct}`
170
+
171
+ export const designGateAnswerMessage = (): string =>
172
+ `Answering here closes a gap between what you want the product to
173
+ do and what gets built; changing nothing and re-running says that
174
+ gap is already closed.
175
+
176
+ \`.gtd/REQUIREMENTS.md\` holds the concerns under
177
+ development. Each open question under \`## Open Questions\` offers
178
+ a few options plus a \`- [ ] _your answer_\` slot. Answer EVERY
179
+ question by ticking exactly one box (\`- [x]\`); for your own
180
+ answer, replace \`_your answer_\` with your text and tick that
181
+ line. Stepping is refused while any question is unanswered — with one
182
+ escape: change nothing and re-run to advance with the questions
183
+ unanswered.
184
+
185
+ You can also leave a footnote alongside an answer — it never
186
+ substitutes for ticking a box, which is still required before
187
+ stepping is allowed:
188
+
189
+ ${footnoteRules}
190
+ What each change does next (then run \`gtd land\`):
191
+ - **Accept as-is** — change nothing and re-run to advance with the questions unanswered — the plan stands as written.
192
+ - **Revise answers** — tick exactly one option per open question (replace \`_your answer_\` for your own) to send it back for the agent to fold your answers in, or delete a question to skip it. To accept the plan as-is instead, revert everything and re-run — a clean tree is the only accept gesture.
193
+ `
194
+
195
+ export const architectureAuthorPrompt = (): string =>
196
+ `${styleBlock}
197
+
198
+ ${styleFormatContract}
199
+
200
+ ${stateFileRules}
201
+ ${footnoteFoldIn}
202
+ - The only state files this turn touches are
203
+ \`.gtd/ARCHITECTURE.md\` (write it) and \`.gtd/REQUIREMENTS.md\`
204
+ (delete once folded in) — no other files for notes or output
205
+ - You do not resume the design conversation — a separate
206
+ machine, its own memory, a cold read every time. Read
207
+ \`.gtd/REQUIREMENTS.md\` (the settled, ordered, classified
208
+ concerns) in full; treat every decision there, PRODUCT or
209
+ TECHNICAL alike, as settled — never re-open it
210
+ - Cold means no memory of triage's own back-and-forth, not no
211
+ git access. This process started at commit
212
+ \`${start()}\`. Find the first turn yourself: run
213
+ \`git rev-list --ancestry-path ${start()}..HEAD | tail -1\`
214
+ then \`git show\` it to see what started this process — a
215
+ hand-edit, a scratch note, or both
216
+ - Once \`.gtd/ARCHITECTURE.md\` is written, delete
217
+ \`.gtd/REQUIREMENTS.md\` — folded in, it must not linger. Leave
218
+ everything uncommitted and finish
219
+
220
+ ## First lap
221
+
222
+ - Develop \`.gtd/ARCHITECTURE.md\` from those concerns: for each,
223
+ in order, work out the *how*, building on the settled *what*
224
+ - You now know the *how*, so you know each concern's file footprint
225
+ — list each concern's primary paths. Merge concerns whose
226
+ footprints center on the same files into one, unless the later
227
+ one only consumes an interface the earlier one creates (keeps a
228
+ build-on-top sequence from collapsing into one blob). This
229
+ authority is to merge only, never to split — the whole problem
230
+ is over-granularity
231
+ - Record every merge under \`## Merged Concerns\`,
232
+ carrying both merged requirements verbatim so spec review
233
+ still covers each independently
234
+ - A merge raises no open question and stops for no
235
+ human — do not route it to \`architecture.gate\` for a veto; the
236
+ human sees it when reviewing the plan, and spec review is the
237
+ real safety net
238
+ - Prefer fewer, larger packages — the smallest independently
239
+ valuable change, not the smallest change that compiles
240
+ - Every open point here is TECHNICAL — triage already resolved
241
+ the product ones, one phase earlier. PERMISSIVE: answer it
242
+ yourself unless you genuinely cannot defend a default; a wrong
243
+ technical call is still caught at spec review
244
+
245
+ ${questionBar}
246
+ ## Return lap
247
+
248
+ ${questionBarReturn}`
249
+
250
+ export const architectSystem = (): string =>
251
+ `${architectPersona}
252
+
253
+ ${agentConduct}`
254
+
255
+ export const architectureDecomposePrompt = (): string =>
256
+ `${styleBlock}
257
+
258
+ ${stateFileRules}
259
+ - The only state files this turn touches are the package files
260
+ under \`.gtd/packages/\` and \`.gtd/ARCHITECTURE.md\` (deleted) —
261
+ no other files for notes or output
262
+ - Work from \`.gtd/ARCHITECTURE.md\` if you wrote it earlier this
263
+ conversation, otherwise read it (the converged technical
264
+ plan). It already lists an ordered set of concerns with every
265
+ merge/split judgement made — this turn is a mechanical
266
+ write-out, not a planning one. A \`## Merged Concerns\` heading
267
+ there records those merges, never a concern of its own: write
268
+ no package file for it
269
+ - Write one package file per concern, in the settled order,
270
+ under \`.gtd/packages/\` (e.g. \`.gtd/packages/01-name.md\`,
271
+ \`02-name.md\`, ...), each carrying that concern's
272
+ requirement(s) — both, independently, if merged — its
273
+ independent tasks, and each task's acceptance criteria as
274
+ \`- [ ]\` checkboxes and relevant paths
275
+ - Do not merge or split concerns here — that judgement already
276
+ happened; carry the settled grouping over verbatim. No
277
+ package file may reference any other \`.gtd/\` file
278
+ - Once written, delete \`.gtd/ARCHITECTURE.md\`. Leave everything
279
+ uncommitted and finish
280
+ `
281
+
282
+ export const architectureGateAnswerMessage = (): string =>
283
+ `Answering here closes a gap between what you want built and how
284
+ it actually gets built; changing nothing and re-running says
285
+ that gap is already closed.
286
+
287
+ \`.gtd/ARCHITECTURE.md\` holds the technical plan under
288
+ development. Each open question under \`## Open Questions\` offers
289
+ a few options plus a \`- [ ] _your answer_\` slot. Answer EVERY
290
+ question by ticking exactly one box (\`- [x]\`); for your own
291
+ answer, replace \`_your answer_\` with your text and tick that
292
+ line. Stepping is refused while any question is unanswered — with one
293
+ escape: change nothing and re-run to advance with the questions
294
+ unanswered.
295
+
296
+ You can also leave a footnote alongside an answer — it never
297
+ substitutes for ticking a box, which is still required before
298
+ stepping is allowed:
299
+
300
+ ${footnoteRules}
301
+ What each change does next (then run \`gtd land\`):
302
+ - **Accept as-is** — change nothing and re-run to advance with the questions unanswered — the plan stands as written.
303
+ - **Revise answers** — tick exactly one option per open question (replace \`_your answer_\` for your own) to send it back for the agent to fold your answers in, or delete a question to skip it. To accept the plan as-is instead, revert everything and re-run — a clean tree is the only accept gesture.
304
+ `
305
+
306
+ export const packagesItemBuildingPrompt = (pkg: string): string =>
307
+ `${stateFileRules}
308
+ - The only state file this turn may write is \`.gtd/SATISFIED.md\`;
309
+ never delete the package file (the spec-review gate reads it
310
+ after you)
311
+ - The package to implement is \`${pkg}\`
312
+ - First check its acceptance criteria against the current tree —
313
+ an earlier fix turn may already satisfy them. If **every**
314
+ criterion is met, implement nothing: write \`.gtd/SATISFIED.md\`
315
+ with each criterion's concrete evidence (commit, file, or
316
+ symbol), change nothing else, and finish. Otherwise implement
317
+ normally and skip that file
318
+ - Implement every task the package describes, no more, no less,
319
+ fanning independent ones out to parallel subagents where your
320
+ harness supports it; leave other package files untouched
321
+ - Leave the package file in place, everything uncommitted, then
322
+ finish your turn
323
+ `
324
+
325
+ export const builderSystem = (): string =>
326
+ `${builderPersona}
327
+
328
+ ${agentConduct}`
329
+
330
+ export const packagesItemFixSuitePrompt = (): string =>
331
+ `${stateFileRules}
332
+ ${fixFeedbackPrompt}
333
+ - If the only way to green the suite is another package's work,
334
+ make the smallest change that gets there — that package can
335
+ then legitimately report itself already satisfied later
336
+ - Leave everything uncommitted and finish your turn — do not commit
337
+ `
338
+
339
+ export const packagesItemFixSpecPrompt = (pkg: string): string =>
340
+ `${stateFileRules}
341
+ - The only state file this turn touches is
342
+ \`.gtd/SPEC_FEEDBACK.md\` — address it, then delete it
343
+ - Read it (the reviewer's concerns) and the package spec
344
+ (\`${pkg}\`), then fix the code to
345
+ resolve every concern
346
+ - Delete \`.gtd/SPEC_FEEDBACK.md\` once resolved; leave everything
347
+ else uncommitted and finish your turn
348
+ `
349
+
350
+ export const healthJudgeMessage = (): string =>
351
+ `The check is still red, and this isn't the first round —
352
+ \`.gtd/FEEDBACK.md\` holds this round's output, and the previous round's
353
+ is in history. Run \`gtd judge answer\` and pipe a
354
+ verdict — identical, new-failure, or progress — or land (with or
355
+ without an edit of your own) to accept the conservative default
356
+ (retry the fix) with no verdict recorded.
357
+ `
358
+
359
+ export const healthDescribePrompt = (): string =>
360
+ `${stateFileRules}
361
+ - The only state file this turn writes is \`.gtd/ESCALATION.md\`
362
+ - Read \`.gtd/FEEDBACK.md\` (this round's failing check output),
363
+ earlier rounds' from history (\`git log -p -- .gtd/FEEDBACK.md\` —
364
+ this may be the first round, with no prior round to compare), and
365
+ the code your own earlier attempts touched
366
+ - Write \`.gtd/ESCALATION.md\`: what is failing, why the previous
367
+ attempts did not resolve it, and concrete suggested approaches to
368
+ solve it
369
+ - Never fix the code yourself — this turn only writes the document
370
+ `
371
+
372
+ export const escalationSystem = (): string =>
373
+ `${escalationPersona}
374
+
375
+ ${agentConduct}`
376
+
377
+ export const healthStopMessage = (): string =>
378
+ `The agent could not get the check to pass after repeated attempts,
379
+ and has written \`.gtd/ESCALATION.md\`: what is failing, why the
380
+ previous attempts didn't resolve it, and suggested approaches.
381
+
382
+ Edit it — narrow it, redirect it, add what you know — or land it
383
+ untouched to hand it to the next fix turn as-is.
384
+ `
385
+
386
+ export const healthExhaustedMessage = (): string =>
387
+ `Escalation attempts are exhausted — this is the second round, and
388
+ the check is still red. \`.gtd/ESCALATION.md\` holds the last
389
+ unresolved analysis, and \`.gtd/FEEDBACK.md\` the last failing
390
+ output.
391
+
392
+ Edit \`.gtd/ESCALATION.md\` with fresh instructions for the next fix
393
+ turn, or land untouched to give it one more attempt at the same
394
+ analysis.
395
+ `
396
+
397
+ export const packagesItemSpecPreMessage = (): string =>
398
+ `Judging whether the code already satisfies each requirement in the
399
+ package spec, before spending a full review turn. Run \`gtd judge
400
+ answer\` and pipe a verdict per section — or land untouched to run
401
+ the full review (the conservative default; a skipped judgment
402
+ never suppresses anything).
403
+ `
404
+
405
+ /** The sections a pre-judge could not clear, when it cleared the rest. */
406
+ const specScope = (failing: readonly string[]): string =>
407
+ failing.length > 0
408
+ ? `- A pre-judge already found the other sections satisfied. Confine
409
+ your review to only these sections:
410
+ ${failing.map((title) => ` - ${title}\n`).join("")}`
411
+ : ""
412
+
413
+ export const packagesItemSpecReviewPrompt = (
414
+ pkg: string,
415
+ failing: readonly string[] = [],
416
+ ): string =>
417
+ `${styleBlock}
418
+
419
+ You are reviewing a freshly-built work package against its own
420
+ spec.
421
+
422
+ ${stateFileRules}
423
+ - The only state file this turn touches is
424
+ \`.gtd/SPEC_FEEDBACK.md\` — write it only when you find problems
425
+ - The package spec is \`${pkg}\`
426
+ ${specScope(failing)}- Verify the implementation against it: tasks done, criteria
427
+ met, code sound and consistent with the codebase. No diff is
428
+ given — read the range yourself, from \`${start()}\`
429
+ to the working tree, process-wide (it can span earlier
430
+ packages)
431
+ - You own that bar; nothing downstream re-weighs your findings
432
+ - Write nothing when the package fully satisfies its spec —
433
+ silence is your approval. Otherwise write
434
+ \`.gtd/SPEC_FEEDBACK.md\` listing what would violate the spec if
435
+ it shipped unaddressed, specific enough to act on, each as its
436
+ own \`## \` heading
437
+ - Never fix anything yourself and never delete the package
438
+ file — a later step owns that
439
+ `
440
+
441
+ export const specReviewerSystem = (): string =>
442
+ `${specReviewerPersona}
443
+
444
+ ${agentConduct}`
445
+
446
+ export const buildFixPrompt = (): string =>
447
+ `${stateFileRules}
448
+ ${fixFeedbackPrompt}
449
+ - Leave everything uncommitted — do not commit
450
+ `
451
+
452
+ export const finisherSystem = (): string =>
453
+ `${finisherPersona}
454
+
455
+ ${agentConduct}`
456
+
457
+ export const buildFixQualityPrompt = (): string =>
458
+ `${stateFileRules}
459
+ - Read \`.gtd/QUALITY.md\` — one \`## \` chunk per quality dimension
460
+ that found something blocking. Merge duplicate findings across
461
+ dimensions FIRST, then fix every chunk
462
+ - Delete \`.gtd/QUALITY.md\` once every finding is resolved
463
+ - Leave everything else uncommitted and finish your turn
464
+ `
465
+
466
+ export const buildQualityReviewingPrompt = (lens: string): string =>
467
+ `${stateFileRules}
468
+ - The only state file this turn writes is \`.gtd/QUALITY.md\` — no
469
+ other files for notes or output
470
+ - Review the whole assembled change, from \`${start()}\`
471
+ to the working tree, through this ONE quality lens only —
472
+ \`${lens}\`, already loaded as this turn's own skill
473
+ - Where you find something blocking, APPEND a \`## \` chunk to
474
+ \`.gtd/QUALITY.md\` describing it — never overwrite what an
475
+ earlier dimension already wrote there
476
+ - Write nothing when nothing is blocking under this lens — a
477
+ clean turn IS this dimension's approval
478
+ - Touch no other state file, and leave everything uncommitted
479
+ `
480
+
481
+ export const reviewerSystem = (): string =>
482
+ `${reviewerPersona}
483
+
484
+ ${agentConduct}`
485
+
486
+ export const buildReviewAwaitReviewMessage = (base: string): string =>
487
+ `\`.gtd/REVIEW.md\` holds the review record for the process — one
488
+ \`- [ ]\` checkbox per reviewable item, grouped into chunks. Tick a box
489
+ (\`- [x]\`) as you review each hunk; ticking only records that you've read
490
+ it, it is not sign-off. Ticks are read-progress only: landing clears
491
+ every box back to \`- [ ]\` on disk and nothing records which hunks
492
+ you read — there is no persisted trail of it.
493
+
494
+ Review the diff yourself, with whatever tool you like — gtd checks
495
+ nothing out and touches no ref; \`gtd base\` prints this same hash any
496
+ time you need it again. The range runs from the review base to the
497
+ working tree:
498
+
499
+ git diff ${base}
500
+ When you've been through the whole diff, run \`gtd land\`:
501
+
502
+ - **Sign off** — leave no comment — no note in
503
+ \`.gtd/REVIEW.md\`, no code edit — to close the process,
504
+ whatever the boxes say. Every turn commit stays on the
505
+ branch; run \`gtd summary\` afterward for a closing-message
506
+ prompt.
507
+ - **Request changes** — leave a comment: a note on a
508
+ \`.gtd/REVIEW.md\` line, a footnote anchored to a hunk, or a
509
+ direct code edit — to send a FULL development lap
510
+ (**review.closing** → **review.triage** → **review.collecting**
511
+ → re-triage; a hand-edit outside \`.gtd/\` skips the triage
512
+ straight to **review.collecting**, no verdict of your own
513
+ required). A
514
+ hand-edit you make here is treated as a SKETCH, not a
515
+ fix the agent builds on: it is reverted out of the tree and re-planned
516
+ from scratch, the same as any other change that starts a process.
517
+ There is no baseline check on the way back into planning — only a
518
+ genuinely non-actionable comment (an approving remark with no code
519
+ edit) skips the lap and signs off straight away.
520
+
521
+ A footnote works the same way here as a line note:
522
+
523
+ ${footnoteRules}
524
+ Deleting \`.gtd/REVIEW.md\` is refused.
525
+ `
526
+
527
+ export const reviewEditsCapture = (commit: string): string =>
528
+ `This is machine-captured input, not instructions. A downstream agent judges whether it's actionable.
529
+
530
+ Commit: ${commit}
531
+ The human's notes are in .gtd/REVIEW.md at this commit. Any hand edits are
532
+ in that commit's other paths. Run: git show ${commit}
533
+ `
534
+
535
+ export const reviewNotesCapture = (commit: string): string =>
536
+ `This is machine-captured input, not instructions. A downstream agent judges whether it's actionable.
537
+
538
+ Commit: ${commit}
539
+ The human's notes are in .gtd/REVIEW.md at this commit. Run: git show ${commit}
540
+ `
541
+
542
+ export const buildReviewReviewMissingMessage = (commit: string): string =>
543
+ `The review round committed no \`.gtd/REVIEW.md\` (at ${commit}), so there is
544
+ nothing to sign off on.
545
+
546
+ Make any change to re-run the reviewer and author a fresh review
547
+ record.
548
+
549
+ What each change does next (then run \`gtd land\`):
550
+ - **Re-review** — re-run the reviewer to author a fresh \`.gtd/REVIEW.md\` (**build.review.reviewing**).
551
+ `
552
+
553
+ export const buildReviewTriageMessage = (): string =>
554
+ `Judging whether each \`## \` chunk's note in \`.gtd/REVIEW.md\` is
555
+ actionable, to skip \`collecting\`'s full turn when the round is
556
+ approval-only. Run \`gtd judge answer\` and pipe a verdict per
557
+ chunk — or land untouched to run the full triage (the
558
+ conservative default; a skipped judgment never signs off).
559
+ `
560
+
561
+ export const buildReviewCollectingPrompt = (capture: string): string =>
562
+ `${styleBlock}
563
+
564
+ ${styleFormatContract}
565
+
566
+ You are judging and classifying a round of review feedback.
567
+
568
+ ${stateFileRules}
569
+ ${footnoteFoldIn}
570
+ - The only state file this turn touches is \`.gtd/REQUIREMENTS.md\` —
571
+ you classify, you do not build
572
+
573
+ The raw review material is:
574
+
575
+ ${capture}
576
+ It names a commit. Work from what you already reviewed if you
577
+ wrote today's review earlier this conversation; otherwise read
578
+ that commit's diff yourself first.
579
+
580
+ The round is actionable if any of these hold:
581
+
582
+ - The human left a note on \`.gtd/REVIEW.md\`. A note is a mandatory
583
+ concern below
584
+ - The human added a code comment this round, even a plain-prose
585
+ one — describe it as a concern, and note the comment line
586
+ itself is transient: it must not survive the lap that
587
+ satisfies it
588
+ - The human hand-edited non-comment code this round — no longer
589
+ a committed intent to build on, but a sketch like the entry
590
+ commit's own diff. Describe what it was reaching for; expect
591
+ the next lap to re-derive it from scratch, never call it final
592
+
593
+ Not actionable only when none of the above holds — nothing but an
594
+ approving remark, no code edit, no substantive note. Never invent
595
+ actionability, and never dismiss a real note or edit as approval.
596
+
597
+ - If actionable: write \`.gtd/REQUIREMENTS.md\` with an ordered
598
+ list of concerns, each PRODUCT or TECHNICAL — the shape
599
+ \`design.triage\` builds, one \`## <heading>\` per concern in
600
+ build order. Fold every note, comment, and hand-edit in under
601
+ its concern. Raise no open questions here — \`design.triage\`
602
+ owns that later. Then finish
603
+ - If not: finish without writing anything — changing nothing is
604
+ the sign-off
605
+ `
606
+
607
+ export const buildReviewReviewingPrompt = (base: string): string =>
608
+ `${styleBlock}
609
+
610
+ ${styleFormatContract}
611
+
612
+ ${stateFileRules}
613
+ - The only state file this turn touches is \`.gtd/REVIEW.md\` —
614
+ no other files for notes or output
615
+
616
+ Write \`.gtd/REVIEW.md\` in this exact format, to help a human
617
+ review the changes:
618
+
619
+ - First non-blank line: \`# Review: ${head().slice(0, 7)}\`
620
+ - Somewhere in the document: \`<!-- base: ${base} -->\`
621
+ - At least one \`## <Chunk Title>\` heading grouping hunks
622
+ semantically (same feature/refactor/fix, across files), each
623
+ with a short explanation of what changed and why, then one
624
+ pointer per hunk (\`./\`-relative path, optional \`#line\`;
625
+ checkboxes are for the human, not you). Put the note's
626
+ opening line right on the pointer's line:
627
+
628
+ - [ ] ./path/to/file.ts#42 — what this hunk does
629
+
630
+ Continue a longer note below the pointer, indented exactly two spaces
631
+ — never four or more, which reads as a code block and never
632
+ reflows:
633
+
634
+ - [ ] ./path/to/file.ts#42 — what this hunk does
635
+ and here is more detail, continued below it
636
+
637
+ A note sitting entirely on the line(s) beneath the pointer is
638
+ also valid. Either way, the note must never start with a bare \`./path\` token
639
+ — that parses as a second pointer, not a note
640
+ No diff is given — read the changes yourself. The range runs
641
+ from \`${base}\` to the working tree (committed turns
642
+ plus anything pending); on a feedback round that's the previous
643
+ review's boundary, so it covers only what's new.
644
+
645
+ Leave \`.gtd/REVIEW.md\` uncommitted and finish.
646
+ `
647
+
648
+ /** `gtd summary`'s prompt: printed cold, no session identity, no diff inlined. */
649
+ export const summaryPrompt = (it: SummaryContext): string => {
650
+ const human =
651
+ it.humanCommits.length > 0
652
+ ? `The human contributed at these commits,
653
+ oldest to newest:
654
+ ${it.humanCommits.map((c) => `- \`${c.hash}\` (entering \`${c.state}\`)\n`).join("")}
655
+ `
656
+ : `The human left no comment or edit this process —
657
+ every commit is machine-authored.
658
+ `
659
+ return `${styleBlock}
660
+
661
+ - Write the closing message for the process HEAD closes or sits inside —
662
+ for a squash, an amend, or a PR body. Starting cold: read every
663
+ decision out of the commits below, not assumed context
664
+ - Cover the motivation, the decisions, the trade-offs, and the
665
+ high-level architectural changes — never which files changed; \`git
666
+ diff --stat\` is for that, not this message
667
+ - If the range removes or renames a documented config key, CLI flag, or
668
+ workflow state — a public surface, not an internal one — add a literal
669
+ \`BREAKING CHANGE:\` footer naming what disappears. A \`!\` on the type
670
+ prefix alone (\`feat!:\`/\`refactor!:\`) is NOT enough: this repo's own
671
+ commit-analyzer has missed that marker before, cutting no release
672
+ until a follow-up commit carried the literal footer instead
673
+
674
+ The process's entry commit is \`${it.entryCommit}\`. ${human}Inspect the range: \`git log ${it.processBase}..${it.processTip}\`
675
+ and \`git diff ${it.processBase} ${it.processTip}\` — exactly what
676
+ a squash or PR body should describe.
677
+
678
+ Token cost: ${it.processCost}
679
+ ${it.processCostByModel.map((m) => `- ${m.model}: ${m.cost}\n`).join("")}
680
+ Print the closing message and stop — this writes nothing itself.
681
+ `
682
+ }