@pmelab/gtd 2.7.0 → 3.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.
- package/README.md +106 -1111
- package/bin/gtd-loop +43 -23
- package/dist/gtd.bundle.mjs +2281 -3387
- package/docs/cli.md +255 -0
- package/docs/configuration.md +377 -0
- package/docs/design/configurable-state-machine.md +1439 -0
- package/docs/design/delta-purity-plan.md +283 -0
- package/docs/design/pattern-machine-plan.md +164 -0
- package/docs/design/scripted-actor.md +289 -0
- package/docs/design/state-file-association.md +112 -0
- package/docs/design/steering-file-loops.md +164 -0
- package/docs/design/work-packages.md +194 -0
- package/docs/development.md +101 -0
- package/docs/examples/advanced-workflow.md +428 -0
- package/docs/loop.md +104 -0
- package/docs/upgrading.md +125 -0
- package/package.json +3 -2
- package/schema.json +6 -73
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# Example: the full grilling → architecting → decompose → picking → review machine
|
|
2
|
+
|
|
3
|
+
This is the fuller machine gtd shipped as its bundled default before the bundled
|
|
4
|
+
default was drastically simplified (see
|
|
5
|
+
[STATES.md §10](../../STATES.md#10-the-bundled-default-workflow) for what ships
|
|
6
|
+
today — including the two steering-file validation loops the current default
|
|
7
|
+
carries over `.gtd/TODO.md` and `.gtd/REVIEW.md`, which this example's own
|
|
8
|
+
`grilling`/`reviewing` phases predate and don't validate). It is preserved here
|
|
9
|
+
as a copy-paste-ready `.gtdrc` recipe for anyone who wants the heavier shape
|
|
10
|
+
back.
|
|
11
|
+
|
|
12
|
+
Compared to the simplified bundled default, this machine adds:
|
|
13
|
+
|
|
14
|
+
- **Two-phase human-in-the-loop planning with Q&A loops** — `grilling` ⇄
|
|
15
|
+
`grilling-answer` develops a product-level plan from `.gtd/TODO.md` one open
|
|
16
|
+
question at a time; `architecting` ⇄ `architecting-answer` repeats the same
|
|
17
|
+
shape for `.gtd/ARCHITECTURE.md`, the technical plan built on top of the
|
|
18
|
+
converged product plan.
|
|
19
|
+
- **Task decomposition** — `decompose` turns the converged architecture into an
|
|
20
|
+
ordered set of self-contained task files under `.gtd/tasks/`.
|
|
21
|
+
- **The deterministic `picking` queue arbiter** — a `script` state that feeds
|
|
22
|
+
tasks into `.gtd/NEXT.md` one at a time, with a per-task `building` →
|
|
23
|
+
`checking`/`fixing` loop, until the queue empties.
|
|
24
|
+
- **Agent-prepared review** — `reviewing` has the agent write `.gtd/REVIEW.md`
|
|
25
|
+
summarizing the full cycle diff for a human to check before `await-review`
|
|
26
|
+
resolves an approval or feedback.
|
|
27
|
+
- **A squash finale** — approval at `await-review` moves to `squashing` (the
|
|
28
|
+
agent authors `.gtd/COMMIT_MSG.md`) and then `done`, a `commit:` state that
|
|
29
|
+
squashes the whole cycle into one commit. The simplified bundled default drops
|
|
30
|
+
this: it rests at `idle` on approval instead and leaves every turn commit in
|
|
31
|
+
history for the human to squash (or not) however they choose.
|
|
32
|
+
|
|
33
|
+
This example also carries `file:`/`mode:` annotations on every state that rests
|
|
34
|
+
on a steering file (see the state table below and
|
|
35
|
+
[docs/design/state-file-association.md](../design/state-file-association.md)) —
|
|
36
|
+
it is the LSP-heavy flow, with `gtd lsp` dispatching document symbols/code
|
|
37
|
+
actions/diagnostics off those declarations rather than a hardcoded basename:
|
|
38
|
+
`grilling`/`grilling-answer` and `architecting`/`architecting-answer` are
|
|
39
|
+
`qa`-format (`vars.todoFile`/`vars.architectureFile` respectively — a new
|
|
40
|
+
`architectureFile` var joins `testCommand`), `reviewing`/`await-review` are
|
|
41
|
+
`review`-format (`vars.reviewFile`), and `fixing`/`escalate` declare `file:`
|
|
42
|
+
alone (`vars.feedbackFile` is plain text, no LSP format).
|
|
43
|
+
|
|
44
|
+
Paste the block below under a top-level `workflow:` key in your own `.gtdrc` (or
|
|
45
|
+
`.gtdrc.yaml`) — it's the complete definition, unmodified in content from the
|
|
46
|
+
version this example is frozen from, only re-indented to nest under `workflow:`.
|
|
47
|
+
See [Configuration](../configuration.md) for the `.gtdrc` schema this slots
|
|
48
|
+
into.
|
|
49
|
+
|
|
50
|
+
## State table
|
|
51
|
+
|
|
52
|
+
| State | Actor | Content | `on` | Retry | Model | File | Mode |
|
|
53
|
+
| --------------------- | ----- | ------- | --------------------------------------------------------------------------------- | ------------------ | ------- | ----------------------- | -------- |
|
|
54
|
+
| `idle` (initial) | human | message | `* **` → `grilling` | — | — | — | — |
|
|
55
|
+
| `grilling` | agent | prompt | `* **` → `grilling-answer` | — | `smart` | `vars.todoFile` | `qa` |
|
|
56
|
+
| `grilling-answer` | human | message | `C` → `architecting`; `* **` → `grilling` | — | — | `vars.todoFile` | `qa` |
|
|
57
|
+
| `architecting` | agent | prompt | `* **` → `architecting-answer` | — | `smart` | `vars.architectureFile` | `qa` |
|
|
58
|
+
| `architecting-answer` | human | message | `C` → `decompose`; `* **` → `architecting` | — | — | `vars.architectureFile` | `qa` |
|
|
59
|
+
| `decompose` | agent | prompt | `* .gtd/tasks/**` → `picking` | — | — | — | — |
|
|
60
|
+
| `picking` | check | script | `D .gtd/NEXT.md` → `reviewing`; `* .gtd/NEXT.md` → `building`; `C` → `reviewing` | — | — | — | — |
|
|
61
|
+
| `building` | agent | prompt | `* **` → `checking` | — | — | — | — |
|
|
62
|
+
| `checking` | check | script | `A .gtd/FEEDBACK.md` → `fixing`; `M .gtd/FEEDBACK.md` → `fixing`; `C` → `picking` | — | — | — | — |
|
|
63
|
+
| `fixing` | agent | prompt | `* **` → `checking` | max 3 → `escalate` | — | `vars.feedbackFile` | — |
|
|
64
|
+
| `escalate` | human | message | `* **` → `checking` | — | — | `vars.feedbackFile` | — |
|
|
65
|
+
| `reviewing` | agent | prompt | `* .gtd/REVIEW.md` → `await-review` | — | `smart` | `vars.reviewFile` | `review` |
|
|
66
|
+
| `await-review` | human | message | `D .gtd/REVIEW.md` → `squashing`; `* **` → `grilling` | — | — | `vars.reviewFile` | `review` |
|
|
67
|
+
| `squashing` | agent | prompt | `A .gtd/COMMIT_MSG.md` → `done`; `M .gtd/COMMIT_MSG.md` → `done` | — | — | — | — |
|
|
68
|
+
| `done` | — | commit | (final — squashes the whole cycle, message read from `.gtd/COMMIT_MSG.md`) | — | — |
|
|
69
|
+
|
|
70
|
+
## The `.gtdrc` recipe
|
|
71
|
+
|
|
72
|
+
````yaml
|
|
73
|
+
workflow:
|
|
74
|
+
vars:
|
|
75
|
+
testCommand: npm test
|
|
76
|
+
todoFile: .gtd/TODO.md
|
|
77
|
+
architectureFile: .gtd/ARCHITECTURE.md
|
|
78
|
+
reviewFile: .gtd/REVIEW.md
|
|
79
|
+
feedbackFile: .gtd/FEEDBACK.md
|
|
80
|
+
|
|
81
|
+
states:
|
|
82
|
+
idle:
|
|
83
|
+
actor: human
|
|
84
|
+
initial: true
|
|
85
|
+
message: |
|
|
86
|
+
No active gtd cycle.
|
|
87
|
+
|
|
88
|
+
To start one: write `.gtd/TODO.md` with a short sketch of what you want
|
|
89
|
+
built — a few sentences is enough — then run `gtd step human`.
|
|
90
|
+
on:
|
|
91
|
+
"* **": grilling
|
|
92
|
+
|
|
93
|
+
grilling:
|
|
94
|
+
actor: agent
|
|
95
|
+
file: <%= it.vars.todoFile %>
|
|
96
|
+
mode: qa
|
|
97
|
+
# `model` is an opaque harness hint — gtd never interprets this string, it
|
|
98
|
+
# only passes it through to `gtd next --json`/`gtd status --json` so the
|
|
99
|
+
# driving loop can map it onto whatever models its agent harness
|
|
100
|
+
# provides. "smart" here just names the harness-chosen tier for the
|
|
101
|
+
# heavier planning/reviewing turns; states without a `model` use the
|
|
102
|
+
# harness's default.
|
|
103
|
+
model: smart
|
|
104
|
+
prompt: |
|
|
105
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
106
|
+
state (plans, task specs, review records) — never create, edit, or
|
|
107
|
+
delete anything under `.gtd/` except `<%= it.vars.todoFile %>`, which
|
|
108
|
+
this prompt tells you to write.
|
|
109
|
+
|
|
110
|
+
`<%= it.vars.todoFile %>` holds the plan under development. Read it,
|
|
111
|
+
then develop it into a concrete, product-level plan in this one turn —
|
|
112
|
+
explore the codebase before asking anything, so every open question is
|
|
113
|
+
one the codebase genuinely cannot answer.
|
|
114
|
+
|
|
115
|
+
Scope: product and user-facing decisions only. Leave implementation
|
|
116
|
+
details (file/module structure, data models, tech-stack choices) for
|
|
117
|
+
the next phase (`.gtd/ARCHITECTURE.md`).
|
|
118
|
+
|
|
119
|
+
For every remaining open question, add it under a `## Open Questions`
|
|
120
|
+
heading, one `### <question>` sub-heading each, with a
|
|
121
|
+
`Suggested default: <answer>` line the human can accept as-is. Omit the
|
|
122
|
+
section entirely once there are none.
|
|
123
|
+
|
|
124
|
+
Leave `.gtd/TODO.md` uncommitted and finish your turn — do not commit,
|
|
125
|
+
and do not run `gtd step agent` yourself; the harness does that.
|
|
126
|
+
on:
|
|
127
|
+
"* **": grilling-answer
|
|
128
|
+
|
|
129
|
+
grilling-answer:
|
|
130
|
+
actor: human
|
|
131
|
+
file: <%= it.vars.todoFile %>
|
|
132
|
+
mode: qa
|
|
133
|
+
message: |
|
|
134
|
+
`<%= it.vars.todoFile %>` holds the plan under development, with any
|
|
135
|
+
open questions under `## Open Questions` — each carrying a suggested
|
|
136
|
+
default.
|
|
137
|
+
|
|
138
|
+
To answer a question, edit its entry in place (replace
|
|
139
|
+
`Suggested default: ...` with `Answer: ...`, or annotate further), then
|
|
140
|
+
run `gtd step human`.
|
|
141
|
+
|
|
142
|
+
To accept all suggested defaults as-is and move on to technical
|
|
143
|
+
architecting, run `gtd step human` with no edits.
|
|
144
|
+
on:
|
|
145
|
+
"C": architecting
|
|
146
|
+
"* **": grilling
|
|
147
|
+
|
|
148
|
+
architecting:
|
|
149
|
+
actor: agent
|
|
150
|
+
file: <%= it.vars.architectureFile %>
|
|
151
|
+
mode: qa
|
|
152
|
+
model: smart
|
|
153
|
+
prompt: |
|
|
154
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
155
|
+
state — never create, edit, or delete anything under `.gtd/` except
|
|
156
|
+
`<%= it.vars.architectureFile %>` and `<%= it.vars.todoFile %>`, which
|
|
157
|
+
this prompt tells you to write and delete respectively.
|
|
158
|
+
|
|
159
|
+
Read `<%= it.vars.todoFile %>` (the converged product plan) and
|
|
160
|
+
develop `<%= it.vars.architectureFile %>` from it in this one turn:
|
|
161
|
+
file/module structure, data models, library/tech-stack choices,
|
|
162
|
+
error-handling strategy — the *how*, building on the *what* already
|
|
163
|
+
settled. Do not re-open product-level decisions from
|
|
164
|
+
`<%= it.vars.todoFile %>`; treat them as settled.
|
|
165
|
+
|
|
166
|
+
For every remaining open question, add it under a `## Open Questions`
|
|
167
|
+
heading the same way as the grilling phase (one `### <question>`
|
|
168
|
+
sub-heading, a `Suggested default: <answer>` line). Omit the section
|
|
169
|
+
once there are none.
|
|
170
|
+
|
|
171
|
+
Once `<%= it.vars.architectureFile %>` is written, delete
|
|
172
|
+
`<%= it.vars.todoFile %>` — its content has been folded in and it must
|
|
173
|
+
not linger.
|
|
174
|
+
|
|
175
|
+
Leave everything uncommitted and finish your turn.
|
|
176
|
+
on:
|
|
177
|
+
"* **": architecting-answer
|
|
178
|
+
|
|
179
|
+
architecting-answer:
|
|
180
|
+
actor: human
|
|
181
|
+
file: <%= it.vars.architectureFile %>
|
|
182
|
+
mode: qa
|
|
183
|
+
message: |
|
|
184
|
+
`<%= it.vars.architectureFile %>` holds the technical plan under
|
|
185
|
+
development, with any open questions under `## Open Questions`.
|
|
186
|
+
|
|
187
|
+
To answer a question, edit its entry in place, then run
|
|
188
|
+
`gtd step human`.
|
|
189
|
+
|
|
190
|
+
To accept all suggested defaults as-is and move on to decomposing the
|
|
191
|
+
work, run `gtd step human` with no edits.
|
|
192
|
+
on:
|
|
193
|
+
"C": decompose
|
|
194
|
+
"* **": architecting
|
|
195
|
+
|
|
196
|
+
decompose:
|
|
197
|
+
actor: agent
|
|
198
|
+
prompt: |
|
|
199
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
200
|
+
state — never create, edit, or delete anything under `.gtd/` except the
|
|
201
|
+
task-spec files this prompt tells you to write (under `.gtd/tasks/`),
|
|
202
|
+
and `.gtd/ARCHITECTURE.md`, which it tells you to delete.
|
|
203
|
+
|
|
204
|
+
Read `.gtd/ARCHITECTURE.md` (the converged technical plan) and
|
|
205
|
+
decompose it into an ordered set of self-contained task files under
|
|
206
|
+
`.gtd/tasks/` (e.g. `.gtd/tasks/01-short-name.md`,
|
|
207
|
+
`.gtd/tasks/02-short-name.md`, ...). Order them so the test suite can
|
|
208
|
+
pass again after each one lands; each file is self-contained
|
|
209
|
+
(description, acceptance criteria as `- [ ]` checkboxes, relevant
|
|
210
|
+
paths) since a building turn receives only that one file as context.
|
|
211
|
+
|
|
212
|
+
No task file may reference any other `.gtd/` file, or a requirement to
|
|
213
|
+
preserve/update workflow state — `.gtd/` is machine-managed and gets
|
|
214
|
+
cleaned up as the cycle proceeds.
|
|
215
|
+
|
|
216
|
+
Once the task files are written, delete `.gtd/ARCHITECTURE.md`. Leave
|
|
217
|
+
everything uncommitted and finish your turn.
|
|
218
|
+
on:
|
|
219
|
+
"* .gtd/tasks/**": picking
|
|
220
|
+
|
|
221
|
+
picking:
|
|
222
|
+
actor: check
|
|
223
|
+
script: |
|
|
224
|
+
#!/usr/bin/env bash
|
|
225
|
+
# gtd check turn (the queue arbiter) — the driver (`gtd run`) executes
|
|
226
|
+
# this verbatim, then steps the check actor. Mechanics only: take the
|
|
227
|
+
# first task file (by name) under .gtd/tasks/ into .gtd/NEXT.md, or
|
|
228
|
+
# remove .gtd/NEXT.md when the queue is empty. What NEXT.md's
|
|
229
|
+
# presence/absence MEANS (another task to build vs. the queue closing
|
|
230
|
+
# out to review) is decided by this state's own `on` rules at capture
|
|
231
|
+
# time — never here.
|
|
232
|
+
set +e
|
|
233
|
+
next=$(ls .gtd/tasks/*.md 2>/dev/null | head -n 1)
|
|
234
|
+
if [ -n "$next" ]; then
|
|
235
|
+
printf '%s' "$next" > .gtd/NEXT.md
|
|
236
|
+
else
|
|
237
|
+
rm -f .gtd/NEXT.md
|
|
238
|
+
fi
|
|
239
|
+
on:
|
|
240
|
+
"D .gtd/NEXT.md": reviewing
|
|
241
|
+
"* .gtd/NEXT.md": building
|
|
242
|
+
"C": reviewing
|
|
243
|
+
|
|
244
|
+
building:
|
|
245
|
+
actor: agent
|
|
246
|
+
prompt: |
|
|
247
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
248
|
+
state — never create or edit anything under `.gtd/` except deleting the
|
|
249
|
+
one task file this prompt tells you to delete; never touch
|
|
250
|
+
`.gtd/NEXT.md` yourself — the `picking` state owns it.
|
|
251
|
+
|
|
252
|
+
The task file to implement is: <%~ it.read(".gtd/NEXT.md") %>
|
|
253
|
+
|
|
254
|
+
Read that file and implement EXACTLY the one task it describes — no
|
|
255
|
+
more, no less; leave every other task file under `.gtd/tasks/`
|
|
256
|
+
untouched. Use TDD discipline: one test, then the implementation that
|
|
257
|
+
passes it, then the next — never write all the tests first.
|
|
258
|
+
|
|
259
|
+
Delete the task file once its work is complete and verified. Leave
|
|
260
|
+
everything else uncommitted and finish your turn.
|
|
261
|
+
on:
|
|
262
|
+
"* **": checking
|
|
263
|
+
|
|
264
|
+
checking:
|
|
265
|
+
actor: check
|
|
266
|
+
script: |
|
|
267
|
+
#!/usr/bin/env bash
|
|
268
|
+
# gtd check turn — the driver (`gtd run`) executes this verbatim, then
|
|
269
|
+
# steps the check actor. Mechanics only: run the test suite and record a
|
|
270
|
+
# red run's output as .gtd/FEEDBACK.md. What that output MEANS (another
|
|
271
|
+
# fix round vs escalation) is decided by the workflow's own `on`/`retry`
|
|
272
|
+
# rules at capture time — never here.
|
|
273
|
+
#
|
|
274
|
+
# `it.vars.testCommand` defaults to "npm test" (this workflow's own
|
|
275
|
+
# `vars:` above) — override it with a top-level `.gtdrc`
|
|
276
|
+
# `vars: { testCommand: ... }` key, or a `GTD_VAR_testCommand`
|
|
277
|
+
# environment variable (highest precedence).
|
|
278
|
+
set +e
|
|
279
|
+
mkdir -p .gtd
|
|
280
|
+
<%~ it.vars.testCommand %> > .gtd/.check-output 2>&1
|
|
281
|
+
code=$?
|
|
282
|
+
if [ "$code" -ne 0 ]; then
|
|
283
|
+
if [ -s .gtd/.check-output ]; then
|
|
284
|
+
mv .gtd/.check-output .gtd/FEEDBACK.md
|
|
285
|
+
else
|
|
286
|
+
rm -f .gtd/.check-output
|
|
287
|
+
printf 'npm test failed with exit code %s and produced no output.' "$code" > .gtd/FEEDBACK.md
|
|
288
|
+
fi
|
|
289
|
+
else
|
|
290
|
+
rm -f .gtd/.check-output
|
|
291
|
+
fi
|
|
292
|
+
on:
|
|
293
|
+
"A .gtd/FEEDBACK.md": fixing
|
|
294
|
+
"M .gtd/FEEDBACK.md": fixing
|
|
295
|
+
"C": picking
|
|
296
|
+
|
|
297
|
+
fixing:
|
|
298
|
+
actor: agent
|
|
299
|
+
file: <%= it.vars.feedbackFile %>
|
|
300
|
+
retry:
|
|
301
|
+
max: 3
|
|
302
|
+
otherwise: escalate
|
|
303
|
+
prompt: |
|
|
304
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
305
|
+
state — never create, edit, or delete anything under `.gtd/` except
|
|
306
|
+
`<%= it.vars.feedbackFile %>`, which this prompt tells you to address.
|
|
307
|
+
|
|
308
|
+
Read `<%= it.vars.feedbackFile %>` (the failing test output) and fix
|
|
309
|
+
the code so the suite passes. Keep the change focused — do not
|
|
310
|
+
refactor unrelated code. If the feedback is wrong, empty or delete
|
|
311
|
+
`<%= it.vars.feedbackFile %>` instead of "fixing" a non-issue; the
|
|
312
|
+
machine picks the dispute up either way.
|
|
313
|
+
|
|
314
|
+
Leave everything uncommitted and finish your turn — do not commit.
|
|
315
|
+
on:
|
|
316
|
+
"* **": checking
|
|
317
|
+
|
|
318
|
+
escalate:
|
|
319
|
+
actor: human
|
|
320
|
+
file: <%= it.vars.feedbackFile %>
|
|
321
|
+
message: |
|
|
322
|
+
The agent could not get the check to pass after repeated attempts.
|
|
323
|
+
`<%= it.vars.feedbackFile %>` holds the last failing output.
|
|
324
|
+
|
|
325
|
+
Investigate and fix it yourself (editing code and/or
|
|
326
|
+
`<%= it.vars.feedbackFile %>`), then run `gtd step human` to try the
|
|
327
|
+
check again.
|
|
328
|
+
on:
|
|
329
|
+
"* **": checking
|
|
330
|
+
|
|
331
|
+
reviewing:
|
|
332
|
+
actor: agent
|
|
333
|
+
file: <%= it.vars.reviewFile %>
|
|
334
|
+
mode: review
|
|
335
|
+
model: smart
|
|
336
|
+
prompt: |
|
|
337
|
+
You are an autonomous coding agent. `.gtd/` holds this workflow's own
|
|
338
|
+
state — never create, edit, or delete anything under `.gtd/` except
|
|
339
|
+
`<%= it.vars.reviewFile %>`, which this prompt tells you to write.
|
|
340
|
+
|
|
341
|
+
Write `<%= it.vars.reviewFile %>` to help a human review the cycle's
|
|
342
|
+
full diff (inlined below): group hunks semantically (same
|
|
343
|
+
feature/refactor/fix, even across files), and for each group write a
|
|
344
|
+
short heading, an explanation of what changed and why, and
|
|
345
|
+
`- [ ] ./path/to/file.ts#42` style file pointers (checkboxes are for
|
|
346
|
+
the human to tick, not you).
|
|
347
|
+
|
|
348
|
+
Leave `<%= it.vars.reviewFile %>` uncommitted and finish your turn.
|
|
349
|
+
<% if (it.processDiff.trim()) { %>
|
|
350
|
+
|
|
351
|
+
## Full cycle diff
|
|
352
|
+
|
|
353
|
+
```diff
|
|
354
|
+
<%~ it.processDiff %>
|
|
355
|
+
```
|
|
356
|
+
<% } %>
|
|
357
|
+
on:
|
|
358
|
+
"* .gtd/REVIEW.md": await-review
|
|
359
|
+
|
|
360
|
+
await-review:
|
|
361
|
+
actor: human
|
|
362
|
+
file: <%= it.vars.reviewFile %>
|
|
363
|
+
mode: review
|
|
364
|
+
message: |
|
|
365
|
+
`<%= it.vars.reviewFile %>` holds the review record for the completed
|
|
366
|
+
cycle.
|
|
367
|
+
|
|
368
|
+
To approve: delete `<%= it.vars.reviewFile %>` and run
|
|
369
|
+
`gtd step human`.
|
|
370
|
+
|
|
371
|
+
To request changes: edit `<%= it.vars.reviewFile %>` (or the code)
|
|
372
|
+
with what's wrong — including just ticking its checkboxes — then run
|
|
373
|
+
`gtd step human`; this sends the cycle back through grilling with your
|
|
374
|
+
feedback as the new input.
|
|
375
|
+
on:
|
|
376
|
+
"D .gtd/REVIEW.md": squashing
|
|
377
|
+
"* **": grilling
|
|
378
|
+
|
|
379
|
+
squashing:
|
|
380
|
+
actor: agent
|
|
381
|
+
prompt: |
|
|
382
|
+
You are an autonomous coding agent. The cycle is approved and done.
|
|
383
|
+
`.gtd/` holds this workflow's own state — never create, edit, or delete
|
|
384
|
+
anything under `.gtd/` except `.gtd/COMMIT_MSG.md`, which this prompt
|
|
385
|
+
tells you to write.
|
|
386
|
+
|
|
387
|
+
Write `.gtd/COMMIT_MSG.md` with ONE conventional-commits message for
|
|
388
|
+
the entire cycle (subject line `type(scope): subject`, imperative mood,
|
|
389
|
+
<= 72 characters; a body explaining the why, trade-offs, and key
|
|
390
|
+
decisions). Plain text, no markdown wrapper.
|
|
391
|
+
|
|
392
|
+
Leave `.gtd/COMMIT_MSG.md` uncommitted and finish your turn — entering
|
|
393
|
+
this file squashes the whole cycle into one commit using its content as
|
|
394
|
+
the message.
|
|
395
|
+
<% if (it.processDiff.trim()) { %>
|
|
396
|
+
|
|
397
|
+
## Full cycle diff
|
|
398
|
+
|
|
399
|
+
```diff
|
|
400
|
+
<%~ it.processDiff %>
|
|
401
|
+
```
|
|
402
|
+
<% } %>
|
|
403
|
+
on:
|
|
404
|
+
"A .gtd/COMMIT_MSG.md": done
|
|
405
|
+
"M .gtd/COMMIT_MSG.md": done
|
|
406
|
+
|
|
407
|
+
done:
|
|
408
|
+
commit: '<%~ it.read(".gtd/COMMIT_MSG.md") %>'
|
|
409
|
+
````
|
|
410
|
+
|
|
411
|
+
A clean `gtd step human` at `grilling-answer`/`architecting-answer` (the `C`
|
|
412
|
+
event) accepts the current phase's draft and moves on; any other pending change
|
|
413
|
+
loops back for another round. `picking` is a `script` state whose only job is to
|
|
414
|
+
inspect `.gtd/tasks/` (a tree property patterns can't see directly) and turn it
|
|
415
|
+
into a diff patterns CAN see — see the walkthrough in
|
|
416
|
+
[STATES.md §10](../../STATES.md#10-the-bundled-default-workflow) (the version of
|
|
417
|
+
that section frozen alongside this example) for the full state-by-state
|
|
418
|
+
narrative, including the `on`-declaration-order subtlety at `picking` and the
|
|
419
|
+
`fixing` retry-cap pooling caveat.
|
|
420
|
+
|
|
421
|
+
## See also
|
|
422
|
+
|
|
423
|
+
- [docs/design/work-packages.md](../design/work-packages.md) — the arbiter's
|
|
424
|
+
decision record: why the scripted `picking` state (Option A) was chosen over
|
|
425
|
+
the agent-encoded-verdict, tree-predicate-guard, and template-enumeration
|
|
426
|
+
alternatives, plus the process-per-task topology variant.
|
|
427
|
+
- [STATES.md](../../STATES.md) — the pattern-machine model this recipe compiles
|
|
428
|
+
against (pattern grammar, resolution, retry, the squash lifecycle).
|
package/docs/loop.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Driving the loop
|
|
2
|
+
|
|
3
|
+
gtd (v3, the pattern machine) exposes three commands a loop driver combines:
|
|
4
|
+
|
|
5
|
+
- **`gtd step <actor>`** — authenticate as `<actor>`, match the resolved rest's
|
|
6
|
+
declared patterns against the pending changes, and commit (or squash) the one
|
|
7
|
+
resulting transition. Performs AT MOST one transition — there is no fixpoint
|
|
8
|
+
chain to drive.
|
|
9
|
+
- **`gtd next`** — print the resolved rest's rendered script/prompt/message,
|
|
10
|
+
without mutating anything.
|
|
11
|
+
- **`gtd run`** — execute the resolved rest's emitted script (only for a
|
|
12
|
+
`script`-content rest), then step that state's own actor to capture the
|
|
13
|
+
outcome. The only place gtd spawns a subprocess.
|
|
14
|
+
|
|
15
|
+
A loop is a simple cycle:
|
|
16
|
+
|
|
17
|
+
1. Run `gtd next --json` — see [`cli.md`](cli.md#gtd-next---json) for the exact
|
|
18
|
+
`{state, actor, kind, content, model?}` field shape. `kind` is the dispatch
|
|
19
|
+
key: `"message"` → halt (a human rest); `"script"` → run `gtd run`;
|
|
20
|
+
`"prompt"` → feed `content` to the agent, then `gtd step <actor>` yourself
|
|
21
|
+
once it's done acting. The optional `model` is an opaque string the workflow
|
|
22
|
+
author chose, which you map onto your own harness's model selection if you
|
|
23
|
+
use one.
|
|
24
|
+
2. Repeat until a `"message"` rest halts the loop, or a zero-commit `gtd run` at
|
|
25
|
+
idle settles it (the green terminal signal).
|
|
26
|
+
|
|
27
|
+
A human acts by editing files (e.g. writing/editing `.gtd/TODO.md`, fixing code)
|
|
28
|
+
and then running `gtd step human` to capture the edit as their turn.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
gtd next --json # ask who's up and what they should do
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
See [`skills/loop/SKILL.md`](../skills/loop/SKILL.md) for the agent-facing
|
|
35
|
+
instructions that follow the same pinned contract. `gtd-loop`, installed
|
|
36
|
+
alongside `gtd` (see below), is the packaged, ready-to-run implementation of
|
|
37
|
+
that same script for anyone who doesn't want to drive the loop by hand.
|
|
38
|
+
|
|
39
|
+
## The reference loop driver
|
|
40
|
+
|
|
41
|
+
A minimal bash implementation of the pinned protocol, driving an agent CLI (e.g.
|
|
42
|
+
`claude -p`) against `gtd next --json` output. This is the authoritative
|
|
43
|
+
reference for what a loop driver must do; keep any other implementation
|
|
44
|
+
(including `skills/loop/SKILL.md`) consistent with it rather than editing both
|
|
45
|
+
independently. `bin/gtd-loop` is this exact script, packaged as the `gtd-loop`
|
|
46
|
+
binary, with three additions: it stops with a diagnostic if the same `"prompt"`
|
|
47
|
+
state/content repeat with no progress (see `skills/loop/SKILL.md`'s "Stall
|
|
48
|
+
detection"); it lets `GTD_LOOP_AGENT_CMD` swap in any coding agent CLI in place
|
|
49
|
+
of the default `claude -p`, receiving the prompt via `$GTD_LOOP_PROMPT`; and it
|
|
50
|
+
exports the resolved state's optional `model` hint as `$GTD_LOOP_MODEL`,
|
|
51
|
+
appending `--model "$GTD_LOOP_MODEL"` to the default `claude -p` invocation
|
|
52
|
+
whenever it's non-empty.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
#!/usr/bin/env bash
|
|
56
|
+
set -euo pipefail
|
|
57
|
+
|
|
58
|
+
while true; do
|
|
59
|
+
next_json="$(gtd next --json)"
|
|
60
|
+
state="$(jq -r .state <<<"$next_json")"
|
|
61
|
+
actor="$(jq -r .actor <<<"$next_json")"
|
|
62
|
+
kind="$(jq -r .kind <<<"$next_json")"
|
|
63
|
+
content="$(jq -r .content <<<"$next_json")"
|
|
64
|
+
|
|
65
|
+
if [[ "$kind" == "message" ]]; then
|
|
66
|
+
echo "--- Your turn ($state) ---"
|
|
67
|
+
gtd next
|
|
68
|
+
exit 0
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [[ "$kind" == "script" ]]; then
|
|
72
|
+
head_before="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
|
73
|
+
gtd run
|
|
74
|
+
head_after="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
|
75
|
+
if [[ "$head_before" == "$head_after" ]]; then
|
|
76
|
+
echo "--- Settled ($state: check passed, nothing to do) ---"
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
continue
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# kind == "prompt": feed the prompt to the agent, then close out its turn.
|
|
83
|
+
claude -p "$content" --dangerously-skip-permissions
|
|
84
|
+
gtd step "$actor" >/dev/null
|
|
85
|
+
done
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The driver — not the prompt text — owns ending the agent's turn
|
|
89
|
+
(`gtd step "$actor"` right after the agent acts): every default-workflow agent
|
|
90
|
+
prompt says explicitly not to run `gtd step agent` itself.
|
|
91
|
+
|
|
92
|
+
## Using a different agent
|
|
93
|
+
|
|
94
|
+
`gtd-loop` defaults to
|
|
95
|
+
`claude -p "$GTD_LOOP_PROMPT" --dangerously-skip-permissions`, but the agent
|
|
96
|
+
invocation is swappable: set `GTD_LOOP_AGENT_CMD` to any shell command, and it
|
|
97
|
+
runs with the prompt available as `$GTD_LOOP_PROMPT` (and the resolved state's
|
|
98
|
+
opaque `model` hint, if any, as `$GTD_LOOP_MODEL`) in its environment — an
|
|
99
|
+
adapter that ignores `$GTD_LOOP_MODEL` keeps working unchanged. For example, to
|
|
100
|
+
drive a different agent CLI:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop
|
|
104
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Upgrading to v3 (BREAKING CHANGE)
|
|
2
|
+
|
|
3
|
+
## v3 is a clean break
|
|
4
|
+
|
|
5
|
+
v3 ("the pattern machine") deletes the entire v2 definition model — gates, guard
|
|
6
|
+
functions, actor kinds, interrupt/fallback ladders, capture rules, turn and
|
|
7
|
+
routing rules, `Gtd-Counters` trailers, conflicts, the review checkout window —
|
|
8
|
+
and replaces it with the much smaller pattern machine described in
|
|
9
|
+
[STATES.md](../STATES.md): named states, each with one content kind and an
|
|
10
|
+
ordered map of change-patterns to next states.
|
|
11
|
+
|
|
12
|
+
**All pre-v3 history is unrecognized and resolves to the initial state, by
|
|
13
|
+
design — v1 and v2 subjects alike.** v3's `resolveState`
|
|
14
|
+
(`src/PatternMachine.ts`) only recognizes its own `gtd(<actor>): <state>`
|
|
15
|
+
subject naming a state and an actor the active workflow currently declares;
|
|
16
|
+
everything else — a v1 `gtd: grilling`, a v2 `gtd(agent): building`, a plain
|
|
17
|
+
`chore: …` commit, anything from a foreign repo — parses as unrecognized and
|
|
18
|
+
lands at the workflow's initial state (`idle` in the bundled default). There is
|
|
19
|
+
no special-casing for "this looks like an old gtd commit": the mechanism is
|
|
20
|
+
exactly the same one that already made v1 history inert to v2, and v2 history
|
|
21
|
+
inert to a differently-configured workflow — v3 just applies it uniformly to all
|
|
22
|
+
prior history instead of drawing a v1/v2 line.
|
|
23
|
+
|
|
24
|
+
**Finish or squash any in-flight cycle first.** A repo mid-cycle on v1 or v2 has
|
|
25
|
+
no v3-shaped commit backing its steering files; upgrading mid-cycle lands cold
|
|
26
|
+
at the initial state with those files still pending, which the new workflow's
|
|
27
|
+
`on` patterns will classify as ordinary pending changes, not as the phase they
|
|
28
|
+
used to represent. Finish the cycle (or squash it) on the old binary first, or
|
|
29
|
+
manually clean up the steering files and commit a plain boundary, before
|
|
30
|
+
upgrading.
|
|
31
|
+
|
|
32
|
+
## What died
|
|
33
|
+
|
|
34
|
+
- **Counters.** `Gtd-Counters` trailers, `fixAttemptCap`/`reviewThreshold`
|
|
35
|
+
config keys, and the counter-stamp machinery are gone. The only budget
|
|
36
|
+
affordance left is a state's own `retry: { max, otherwise }`
|
|
37
|
+
(§[STATES.md](../STATES.md#7-retry)) — a plain per-process entry cap
|
|
38
|
+
redirected at write time, with no trailer to read back.
|
|
39
|
+
- **`.gtdrc` keys.** The old `testCommand`, `fixAttemptCap`, `reviewThreshold`,
|
|
40
|
+
`agenticReview`, `squash`, `learning`, `decisionLog`, and `models` keys are
|
|
41
|
+
all gone — `workflow:` and `vars:` are the only two blessed keys (see
|
|
42
|
+
[Configuration](configuration.md)). A check's command now lives inline in its
|
|
43
|
+
own `script:` content, reading a workflow-declared `it.vars` entry (the
|
|
44
|
+
bundled default's `testCommand`, overridable via the top-level `vars:` key or
|
|
45
|
+
a `GTD_VAR_testCommand` environment variable — see
|
|
46
|
+
[Configuration's "Variables"](configuration.md#variables)) rather than a
|
|
47
|
+
blessed `testCommand` config key; squashing is a `commit:` state instead of a
|
|
48
|
+
boolean flag; there is no learning phase, no decision log, and no model
|
|
49
|
+
tiering — a workflow author is free to build any of that shape back with
|
|
50
|
+
states of their own, but gtd no longer bakes it in.
|
|
51
|
+
- **The review checkout window.** v2 rewound HEAD/index to the review base while
|
|
52
|
+
a human review rested, so editors would show the diff directly. Deleted in v3
|
|
53
|
+
(may return later as an explicit state property — not in scope now).
|
|
54
|
+
- **`forceApprove`, content-inspection verdicts.** FEEDBACK.md emptiness,
|
|
55
|
+
checkbox-only REVIEW.md diffs, and doc-structure validation are gone as ENGINE
|
|
56
|
+
mechanisms — verdicts are now expressed purely by which file a turn writes or
|
|
57
|
+
deletes, matched by an ordinary `on` pattern. The bundled default workflow's
|
|
58
|
+
own two validation loops (`todo-validating`/`review-validating`/
|
|
59
|
+
`review-deciding` — see
|
|
60
|
+
[docs/design/steering-file-loops.md](design/steering-file-loops.md)) rebuild
|
|
61
|
+
checkbox-review and doc-structure verdicts as ordinary WORKFLOW data
|
|
62
|
+
(`script`-content states + `on` patterns), not an engine hook: `D REVIEW.md` =
|
|
63
|
+
approve, `M REVIEW.md` = route to the deterministic decider, in the bundled
|
|
64
|
+
default.
|
|
65
|
+
- **`gtd questions` / `gtd changesets` / `gtd review <target>`.** Gone; the v3
|
|
66
|
+
command surface is `step` / `next` / `run` / `status` / `format` / `lsp` (see
|
|
67
|
+
[CLI reference](cli.md)).
|
|
68
|
+
- **Model tiers, the decision log.** No `models` config key, no `Gtd-Decisions`
|
|
69
|
+
trailer scan, no grilling/architecting "prior decisions" context assembled
|
|
70
|
+
from history.
|
|
71
|
+
- **LSP.** Deleted at the v3 rewrite, then resurrected file-format-keyed rather
|
|
72
|
+
than state-keyed (`gtd lsp` — see
|
|
73
|
+
[Development](development.md#the-lsp-server)). The `gtd.openSteeringFile`
|
|
74
|
+
command is BACK (see
|
|
75
|
+
[docs/design/state-file-association.md](design/state-file-association.md)) —
|
|
76
|
+
config-driven rather than the v2 hardcoded state→file map: any state may
|
|
77
|
+
declare a `file:` (an Eta template) and a `mode:` (`qa`/`review`, the file's
|
|
78
|
+
format), the LSP reads that same config the CLI does to build its path→mode
|
|
79
|
+
dispatch, and `gtd.openSteeringFile` resolves the current state and shows its
|
|
80
|
+
`file:`. No mapping declared at all (the bundled default's predecessor shape,
|
|
81
|
+
or any workflow with no `file:`/`mode:`) falls back to basename dispatch
|
|
82
|
+
(`TODO.md`/`REVIEW.md`), same as before this addition.
|
|
83
|
+
|
|
84
|
+
## How to adopt
|
|
85
|
+
|
|
86
|
+
`workflow:` is optional — with no config at all, the bundled default workflow
|
|
87
|
+
applies: a single-shot `grilling` plan, direct `building`, a `checking`/`fixing`
|
|
88
|
+
loop, and a direct-diff `await-review` that rests the cycle back at `idle` on
|
|
89
|
+
approval — no squash; every turn commit stays in history for you to squash
|
|
90
|
+
however you like, or not at all (see
|
|
91
|
+
[STATES.md §10](../STATES.md#10-the-bundled-default-workflow)) — expressed as
|
|
92
|
+
data rather than baked into the engine. The fuller grilling ⇄ grilling-answer /
|
|
93
|
+
architecting ⇄ architecting-answer / decompose / picking / reviewing shape v2
|
|
94
|
+
shipped — including a squash finale — is preserved as a copy-paste `.gtdrc`
|
|
95
|
+
example at [docs/examples/advanced-workflow.md](examples/advanced-workflow.md)
|
|
96
|
+
rather than the bundled default. Nothing to do for a repo that's happy with the
|
|
97
|
+
default shape beyond a normal `npm install -g @pmelab/gtd` upgrade, from a
|
|
98
|
+
settled `idle` boundary.
|
|
99
|
+
|
|
100
|
+
A repo that customized v2's `workflow:` key (actors, gates, guard vocabulary,
|
|
101
|
+
ladders) needs to rewrite it from scratch in the v3 schema — see
|
|
102
|
+
[Configuration](configuration.md) for the schema and a complete worked example.
|
|
103
|
+
There is no automatic migration: the two vocabularies don't map field-for-field
|
|
104
|
+
(guards become patterns, capture rules become `on` targets, counters become
|
|
105
|
+
`retry`), so a v2 `workflow:` config is simply invalid v3 config and fails
|
|
106
|
+
loudly at load time rather than silently misinterpreting.
|
|
107
|
+
|
|
108
|
+
**Re-copy the loop skill.** If you vendor `skills/loop/` into a consuming repo
|
|
109
|
+
or agent harness, upgrading the `gtd` binary also means re-copying that skill
|
|
110
|
+
from this release.
|
|
111
|
+
|
|
112
|
+
## Prior breaking change: the v1 → v2 label grammar (historical)
|
|
113
|
+
|
|
114
|
+
v2 replaced v1's undifferentiated turn labels with six labels carrying the
|
|
115
|
+
branch outcome at capture time, moved steering files under `.gtd/`, and
|
|
116
|
+
introduced `Gtd-Counters` commit trailers. All of that is itself now superseded
|
|
117
|
+
by v3's clean break above — a v1 or v2 repo upgrades to v3 the same way
|
|
118
|
+
(finish/squash any in-flight cycle, then upgrade from a settled boundary);
|
|
119
|
+
there's no reason to upgrade v1 → v2 → v3 in two hops.
|
|
120
|
+
|
|
121
|
+
For maintainers: this repo releases via `semantic-release` reading Conventional
|
|
122
|
+
Commits, and needs **no config change** for a major bump — but the release
|
|
123
|
+
commit/PR **must carry a `BREAKING CHANGE:` footer** (or a `!` after the type)
|
|
124
|
+
for `@semantic-release/commit-analyzer` to compute the next major version rather
|
|
125
|
+
than a minor/patch bump.
|