@pmelab/gtd 2.8.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.
@@ -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 CHANGED
@@ -1,30 +1,34 @@
1
1
  # Driving the loop
2
2
 
3
- gtd splits what used to be one mutating command into three:
3
+ gtd (v3, the pattern machine) exposes three commands a loop driver combines:
4
4
 
5
- - **`gtd step`** — advance the workflow as the **human** actor, to fixpoint.
6
- - **`gtd step-agent`** — advance the workflow as the **agent** actor, to
7
- fixpoint.
8
- - **`gtd next`** — print the prompt for whichever actor is currently awaited,
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,
9
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.
10
14
 
11
- An agent loop is a two-beat protocol repeated forever:
15
+ A loop is a simple cycle:
12
16
 
13
- 1. Run `gtd step-agent` to advance any agent-owned bookkeeping to a fixpoint.
14
- 2. Run `gtd next --json` and read the `actor` field. If it is `"human"`,
15
- **halt** — the human owns the next move, and the agent's job is done for this
16
- turn. If it is `"agent"`, feed `prompt` (when non-null) to the agent, let it
17
- act, then go back to step 1; at a pending checkpoint (`prompt` is null) go
18
- straight back to step 1.
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).
19
26
 
20
- A human acts by editing files (answering questions in `.gtd/TODO.md` or
21
- `.gtd/ARCHITECTURE.md`, annotating `.gtd/REVIEW.md`, fixing code) and then
22
- running `gtd step` to capture the edit as their turn and hand control back to
23
- the agent side of the loop.
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.
24
29
 
25
30
  ```bash
26
- gtd step-agent # advance the machine's own bookkeeping
27
- gtd next --json # ask who's up and what they should do
31
+ gtd next --json # ask who's up and what they should do
28
32
  ```
29
33
 
30
34
  See [`skills/loop/SKILL.md`](../skills/loop/SKILL.md) for the agent-facing
@@ -34,70 +38,66 @@ that same script for anyone who doesn't want to drive the loop by hand.
34
38
 
35
39
  ## The reference loop driver
36
40
 
37
- A minimal bash implementation of the pinned two-beat protocol, driving an agent
38
- CLI (e.g. `claude -p`) against `gtd --json` output. This is the authoritative
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
39
43
  reference for what a loop driver must do; keep any other implementation
40
44
  (including `skills/loop/SKILL.md`) consistent with it rather than editing both
41
- independently.
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.
42
53
 
43
54
  ```bash
44
55
  #!/usr/bin/env bash
45
56
  set -euo pipefail
46
57
 
47
58
  while true; do
48
- # 1. Advance the machine's own agent-owned bookkeeping to a fixpoint.
49
- gtd step-agent --json >/dev/null || true
50
-
51
- # 2. Ask who's up next. `actor` is the single "proceed" signal.
52
- next="$(gtd next --json)"
53
- actor="$(jq -r .actor <<<"$next")"
54
- prompt="$(jq -r .prompt <<<"$next")"
55
-
56
- if [[ "$actor" != "agent" ]]; then
57
- echo "Halting — the human owns the next move."
58
- break
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
59
69
  fi
60
70
 
61
- if [[ "$prompt" == "null" ]]; then
62
- # Agent-driven pending checkpoint: nothing to act on — loop back to
63
- # step 1, whose `gtd step-agent` resumes the mid-chain bookkeeping.
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
64
79
  continue
65
80
  fi
66
81
 
67
- # Agent's turn: feed the prompt to the agent, then let it finish with
68
- # `gtd step-agent` itself (the prompt's tail instructs it to).
69
- claude -p "$prompt" --dangerously-skip-permissions
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
70
85
  done
71
86
  ```
72
87
 
73
- The agent is expected to run `gtd step-agent` itself once it finishes acting on
74
- the prompt (the plain-mode tail says exactly this) — the driver's own
75
- `step-agent` calls exist to advance any bookkeeping the agent doesn't own
76
- (routing commits, test runs) between agent turns.
77
-
78
- The loop halts on `actor: "human"` alone: a human rest (`pending: false`, the
79
- prompt body addresses the human) or a human-driven pending checkpoint
80
- (`pending: true`, resumed by the human's own `gtd step`). Everything the agent
81
- side can drive — agent rests and agent-driven checkpoints — reports
82
- `actor: "agent"`, so multiple agent turns and commits (e.g. successive test/fix
83
- cycles, a force-approved package close) chain without human involvement until an
84
- actual human gate is hit.
85
-
86
- `bin/gtd-loop`, installed as the `gtd-loop` binary, is the packaged
87
- implementation of this exact script — kept in sync with it the same way
88
- `skills/loop/SKILL.md` is. It additionally attempts `gtd step` (not just
89
- `gtd step-agent`) every iteration, so a plain rerun after you've edited a file
90
- at a human gate (no commit needed) picks up your edit and keeps going, and it
91
- halts with a diagnostic if the same state and prompt repeat with no progress
92
- (see `skills/loop/SKILL.md`'s "Stall detection").
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.
93
91
 
94
92
  ## Using a different agent
95
93
 
96
94
  `gtd-loop` defaults to
97
95
  `claude -p "$GTD_LOOP_PROMPT" --dangerously-skip-permissions`, but the agent
98
96
  invocation is swappable: set `GTD_LOOP_AGENT_CMD` to any shell command, and it
99
- runs with the prompt available as `$GTD_LOOP_PROMPT` in its environment. For
100
- example, to drive a different agent CLI:
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
101
 
102
102
  ```bash
103
103
  GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop