@pmelab/gtd 1.9.2 → 2.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.
Files changed (3) hide show
  1. package/README.md +659 -757
  2. package/dist/gtd.bundle.mjs +3288 -2924
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -4,33 +4,69 @@
4
4
  > might be terrible, I don't even know 🤷‍♂️ But otherwise I wouldn't have built it
5
5
  > in the first place. Now I have something that actually helps me.
6
6
 
7
- A git-aware CLI that emits the next prompt for an autonomous coding agent based
8
- on the current repository state — capture an idea, grill it into a plan,
9
- decompose it into work packages, execute with parallel subagents, test,
10
- agentically review each package, and finally walk a human through a review.
7
+ A git-aware CLI that drives a turn-taking loop between a human and an autonomous
8
+ coding agent: capture an idea, grill it into a plan, decompose it into work
9
+ packages, execute with parallel subagents, test, agentically review each
10
+ package, and finally walk a human through a review — squashing the whole cycle
11
+ into one conventional-commits commit at the end.
11
12
 
12
13
  Internally, gtd is a **pure fold** over git history. The decision core
13
14
  (`src/Machine.ts`) is a single IO-free function, `resolve(events)` — **no
14
15
  xstate, no actor, no Effect**. The Effect "edge" (`src/Events.ts`) does all the
15
16
  git/filesystem IO: it reads the **first-parent** commit subjects since the
16
17
  merge-base with the default branch (whole-history fallback when there is no
17
- default branch, when HEAD equals the merge-base, or when there is no merge-base
18
- i.e. budgets engage on the default branch too) plus the working tree, turns
19
- them into a `COMMIT[]` + single terminal `RESOLVE` event stream, and folds them
20
- through the machine. The fold lands on exactly **one** of 19 states, which
21
- selects the prompt. A single run resolves to a single state.
22
-
23
- `resolve()` returns that state plus an optional **`EdgeAction`** (a commit,
24
- revert, test run, or file write). The driver loop (`src/main.ts`) performs the
25
- action, then re-gathers and re-resolves auto-advancing through the
26
- deterministic chain **within one invocation** until it reaches a prompt-bearing
27
- or STOP state. The agent never runs `git commit` itself: every agent leaves its
28
- output **uncommitted**, and the edge commits it with the right flat
29
- `gtd: <phase>` subject on the next hop. The machine stays pure — it only decides
30
- _which_ action; the semantics live in the edge.
31
-
32
- `gtd` is an npm CLI install it, run `gtd` in a repo, and it prints the next
33
- prompt to stdout; a human or any agent reads and follows it.
18
+ default branch, when HEAD equals the merge-base, or when there is no merge-base)
19
+ plus the working tree, turns them into a `COMMIT[]` + single terminal `RESOLVE`
20
+ event stream, and folds them through the machine. The fold lands on exactly
21
+ **one** of 16 states, plus which actor (human or agent) is awaited there. A
22
+ single call resolves to a single state.
23
+
24
+ Steering is entirely **machine-authored commit subjects** there are no marker
25
+ files, sentinels, or auto-advance tails to parse. A turn commit looks like
26
+ `gtd(human): grilling` or `gtd(agent): building`; a routing commit (bookkeeping
27
+ the machine performs itself between turns) looks like `gtd: tests green`.
28
+ `src/Subjects.ts` is the closed grammar both the machine and the edge read.
29
+
30
+ All workflow state lives under **`.gtd/`**: the plan (`.gtd/TODO.md`), work
31
+ packages (`.gtd/01-…/`), review records (`.gtd/REVIEW.md`, `.gtd/FEEDBACK.md`),
32
+ and loop bookkeeping (`.gtd/ERRORS.md`, `.gtd/HEALTH.md`, `.gtd/SQUASH_MSG.md`).
33
+ One rule follows for every agent in the loop: **never touch `.gtd/`** except the
34
+ single file a prompt explicitly grants. A `TODO.md` or `REVIEW.md` at the
35
+ repository root is the project's own file — gtd never reads, consumes, or
36
+ deletes it. (Corollary: don't gitignore `.gtd/` — the workflow commits its state
37
+ through it.)
38
+
39
+ ## Quick start: the two-beat loop
40
+
41
+ gtd splits what used to be one mutating command into three:
42
+
43
+ - **`gtd step`** — advance the workflow as the **human** actor, to fixpoint.
44
+ - **`gtd step-agent`** — advance the workflow as the **agent** actor, to
45
+ fixpoint.
46
+ - **`gtd next`** — print the prompt for whichever actor is currently awaited,
47
+ without mutating anything.
48
+
49
+ An agent loop is a two-beat protocol repeated forever:
50
+
51
+ 1. Run `gtd step-agent` to advance any agent-owned bookkeeping to a fixpoint.
52
+ 2. Run `gtd next --json` and read the `actor` field. If it is `"human"`,
53
+ **halt** — the human owns the next move, and the agent's job is done for this
54
+ turn. If it is `"agent"`, feed `prompt` (when non-null) to the agent, let it
55
+ act, then go back to step 1; at a pending checkpoint (`prompt` is null) go
56
+ straight back to step 1.
57
+
58
+ A human acts by editing files (answering questions in `.gtd/TODO.md`, annotating
59
+ `.gtd/REVIEW.md`, fixing code) and then running `gtd step` to capture the edit
60
+ as their turn and hand control back to the agent side of the loop.
61
+
62
+ ```bash
63
+ gtd step-agent # advance the machine's own bookkeeping
64
+ gtd next --json # ask who's up and what they should do
65
+ ```
66
+
67
+ See [The reference loop driver](#the-reference-loop-driver) for a full script
68
+ implementing this protocol, and [`skills/loop/SKILL.md`](skills/loop/SKILL.md)
69
+ for the agent-facing instructions that follow the same pinned contract.
34
70
 
35
71
  ## Installation
36
72
 
@@ -44,493 +80,515 @@ Or run without installing:
44
80
  npx @pmelab/gtd
45
81
  ```
46
82
 
47
- No config file, no setup subcommand.
48
-
49
- ## Usage
50
-
51
- Run `gtd` from your repository's working directory — it prints the next prompt
52
- to stdout. It takes **no ref argument** — the review base is always
53
- auto-computed. The one exception is `gtd review <target>`: an explicit,
54
- on-demand human review against a chosen base (see
55
- [Review subcommand](#review-subcommand) below).
83
+ No config file, no setup subcommand — `gtd` auto-initializes a `.gtdrc.json`
84
+ schema stub on first run (see [Auto-init](#auto-init)).
56
85
 
57
- On an idle tree outside a process (no steering files, nothing reviewable), `gtd`
58
- now runs a **health check** instead of stopping immediately — `gtd review` is
59
- the only way to start an ad-hoc review when the automatic review base yields no
60
- diff.
86
+ ## Command reference
61
87
 
62
- ## JSON output mode
88
+ ```
89
+ Usage: gtd [command] [options]
63
90
 
64
- Pass `--json` to the default `gtd` invocation to receive machine-readable output
65
- instead of a plain prompt:
91
+ Commands:
92
+ step Advance the workflow as the human actor (to fixpoint)
93
+ step-agent Advance the workflow as the agent actor (to fixpoint)
94
+ next Print the prompt for whichever actor is awaited (no mutation)
95
+ status Predict the next commit and state from the working tree (no mutation)
96
+ review <target> Anchor an ad-hoc human review against a git ref or branch
97
+ format <file> Format a markdown file in place
66
98
 
67
- ```bash
68
- gtd --json
99
+ Options:
100
+ --json Output structured JSON instead of plain text
101
+ --version, -v Print version and exit
102
+ --help, -h Print this help and exit
69
103
  ```
70
104
 
71
- `--json` applies only to the default command. Passing it to `gtd format` is
72
- rejected with exit code 1 and an error on stderr. It is orthogonal to all other
73
- flags (`--verbose`, `--debug`, etc.) each controls exactly one concern.
105
+ `--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
106
+ repository-state work they run outside a repo and in any repo state. Bare
107
+ `gtd` (no subcommand) is a usage error: it prints the help text and exits 1
108
+ without touching the repository. Every other command must be run from the
109
+ **repository root** — gtd derives steering files, diffs, and pathspecs relative
110
+ to cwd, so it refuses with a clear error if invoked from a subdirectory.
74
111
 
75
- ### Output shape
112
+ `--json` is the only long option. Any other `--` option (including a typo like
113
+ `--jsn`) is rejected with a usage error rather than silently ignored, so a
114
+ mistyped flag can never degrade a JSON caller to plain-text mode.
76
115
 
77
- In `--json` mode gtd emits a **single-line JSON object** to stdout:
116
+ ### `gtd step` / `gtd step-agent`
78
117
 
79
- ```json
80
- { "state": "building", "autoAdvance": true, "prompt": "..." }
81
- ```
118
+ Both drive the **same fixpoint loop** — gather → resolve → perform the returned
119
+ edge action repeat differing only in which actor's turn they are allowed to
120
+ capture:
82
121
 
83
- - **`state`** the resolved prompt-bearing `GtdState` (e.g. `"grilling"`,
84
- `"building"`, `"fixing"`, `"clean"`).
85
- - **`autoAdvance`** — the same boolean that selects the loop-tail in plain mode.
86
- `true` means the workflow advances automatically after the agent acts; `false`
87
- means a STOP state was reached and human input is expected.
88
- - **`prompt`** — the full markdown prompt, but with **both loop-control tails
89
- omitted**. In their place, the prompt ends with:
90
- `Complete the steps above, then end your turn — the harness decides what happens next.`
91
- The caller is responsible for reading `autoAdvance` and deciding whether to
92
- run another cycle.
122
+ - **`gtd step`** captures the **human** turn at whichever gate is awaiting one.
123
+ - **`gtd step-agent`** captures the **agent** turn.
93
124
 
94
- ### Loop-ownership division of labor
125
+ **Fixpoint advance.** A single invocation may author several commits: it authors
126
+ the awaited actor's turn commit, then keeps performing any further mid-chain
127
+ routing (a test run, a routing commit, a package close, …) until it reaches a
128
+ rest where a prompt would be shown, or a fixpoint where nothing changed.
129
+ `gtd step`/`gtd step-agent` never print a prompt themselves — that's
130
+ `gtd next`'s job.
95
131
 
96
- In **plain mode** the in-prompt tails own the loop the prompt instructs the
97
- agent to re-run `gtd` when `autoAdvance` is true.
132
+ **Idempotence.** Re-running the same command again once the tree is settled at a
133
+ rest authors **zero** new commits. It exits 0 while the rest still awaits that
134
+ command's actor (an inert empty agent turn, the idle health check); once the
135
+ rest awaits the _other_ actor, the re-run is an out-of-turn refusal — still zero
136
+ commits, but non-zero exit.
98
137
 
99
- In **`--json` mode** the **caller owns the loop** the tails are stripped and
100
- the caller reads `autoAdvance` from the JSON object to decide whether to
101
- iterate.
138
+ **Out-of-turn refusal.** Human and agent turns are strictly separated: the wrong
139
+ mutator always errors, at every state, on clean and dirty trees alike.
140
+ `gtd step-agent` while a human turn is awaited refuses with
141
+ `"<state> awaits a human turn — run \`gtd step\`"`; `gtd
142
+ step`while an agent turn is awaited refuses with`"<state> awaits an agent turn —
143
+ run \`gtd
144
+ step-agent\`"`— exit non-zero, zero commits either way. Human edits made while the agent is awaited (e.g. amendment notes in`.gtd/`package files after the`gtd:
145
+ planning` commit lands) stay pending in the working tree and ride along as input
146
+ to the agent's next captured turn; left unamended, the build proceeds.
102
147
 
103
- Example driver script:
148
+ **Red-test fixpoints exit 0.** A red test run below the fix-attempt cap (or the
149
+ health-fix cap) still writes its findings and commits — it is a normal,
150
+ successful step of the loop, not a failure of the `step`/`step-agent`
151
+ invocation. `step`/`step-agent` only exit non-zero for a genuine refusal or an
152
+ operational error (bad config, missing test binary, corrupted state).
104
153
 
105
- ```bash
106
- #!/usr/bin/env bash
107
- set -euo pipefail
154
+ **Output.** Plain mode prints one `committed: <subject>` line per commit this
155
+ invocation authored (oldest→newest), then a final `state: <state>` line:
108
156
 
109
- while true; do
110
- out="$(gtd --json)"
111
- prompt="$(jq -r .prompt <<<"$out")"
112
- claude -p "$prompt" --dangerously-skip-permissions
113
- jq -e .autoAdvance <<<"$out" >/dev/null || break
114
- done
157
+ ```
158
+ committed: gtd(human): grilling
159
+ committed: gtd: grilled
160
+ state: grilled
115
161
  ```
116
162
 
117
- ### Error behavior
163
+ `--json` emits `{state, actions, commits}` instead (see
164
+ [JSON schemas](#json-schemas)).
118
165
 
119
- Errors are reported **inside** the JSON object rather than as unstructured text:
166
+ ### `gtd next`
167
+
168
+ Pure prompt emitter — it **never mutates** the repository. It reports whichever
169
+ actor is currently awaited and, if the tree is at a genuine rest, the full
170
+ prompt for that actor.
171
+
172
+ **Purity.** No commits, no file writes, no test runs — `gtd next` only gathers
173
+ and resolves.
174
+
175
+ **Dirty-tree refusal.** If the working tree has pending changes outside the
176
+ steering-file set, `gtd next` refuses rather than guess at a prompt for a state
177
+ that hasn't been captured yet:
120
178
 
121
- ```json
122
- { "state": "error", "autoAdvance": false, "prompt": "<message>" }
123
179
  ```
180
+ gtd next: working tree is dirty — run `gtd status` to inspect it, then advance with `gtd step` or `gtd step-agent` (whichever actor is awaited)
181
+ ```
182
+
183
+ **Pending.** If HEAD is mid-chain — bookkeeping the next `step`/`step-agent`
184
+ invocation would perform before reaching a rest — `gtd next` reports
185
+ `pending: true` with no prompt. Mid-chain bookkeeping is invoker-agnostic, so
186
+ either mutator resumes it; the report names the actor whose chain it is. In
187
+ plain mode an agent-driven checkpoint prints `"mid-chain checkpoint — run \`gtd
188
+ step-agent\` to continue, then run \`gtd next\`
189
+ again"`, a human-driven one prints `"mid-chain checkpoint — run \`gtd step\` to
190
+ continue"`.
124
191
 
125
- The process still exits with code 1. Exit codes are otherwise unchanged: 0 on
126
- success, 1 on error.
127
-
128
- ## Steering files
129
-
130
- `gtd` writes and commits temporary steering files that carry workflow state
131
- across runs:
132
-
133
- - **TODO.md** — the current plan, under development during grilling.
134
- - **REVIEW.md** — a guided human review spanning a commit diff. Format:
135
- - `# Review: <short-hash>` heading + `<!-- base: <full-hash> -->` marker
136
- identifying the review base commit
137
- - Per-hunk `- [ ]` checkboxes: ticking them (`- [ ]` → `- [x]`) is the
138
- **approval signal** — checkbox-only edits route to Done; _unchecked_ boxes
139
- never gate the workflow
140
- - Open questions at the top, resolved/addressed items at the bottom
141
- (consistent with TODO.md grilling convention)
142
- - **FEEDBACK.md** — test-failure output, **or** agentic-review findings, to be
143
- fixed. An **empty** FEEDBACK.md from a clean agentic review signals
144
- **approval** (→ Close package).
145
- - **ERRORS.md** — the escalation gate: persistent test-failure output that stops
146
- the loop for a human (written instead of FEEDBACK.md once the fix-attempt cap
147
- is hit; never auto-consumed).
148
- - **HEALTH.md** — idle health-check failure output: written when `testCommand`
149
- fails on a bare idle tree (no `.gtd`, no REVIEW.md, no FEEDBACK.md). Carries
150
- the failure while the dedicated health-fix loop repairs it. Analogous to
151
- FEEDBACK.md but lives on the default-branch idle path rather than inside a
152
- build process. Never written while any other steering file is present.
153
- - **.gtd/** — ordered work packages (one numbered directory each) of
154
- parallelizable subtasks.
155
-
156
- Steering files are **authoritative**: while any exist, `gtd` resumes that
157
- workflow regardless of the last commit (even a non-gtd one). They are **never
158
- garbage-collected automatically** — a stale steering file from an abandoned
159
- branch is resumed exactly like a live one, so you must `rm` files from a
160
- workflow you have abandoned.
161
-
162
- "**Code changes**" below means pending working-tree changes (tracked or
163
- untracked, respecting `.gitignore`) **outside** the steering set. Changes to
164
- steering files are detected separately.
165
-
166
- ## Detection model
167
-
168
- Every run derives the state in **three layers**:
169
-
170
- 1. **Transport pre-pass** — if HEAD is `gtd: transport`, short-circuit to the
171
- Transport state (mixed-reset) before anything else is considered.
172
- 2. **Steering-file precedence** — the presence of `ERRORS.md` / `FEEDBACK.md` /
173
- `HEALTH.md` / `.gtd/` / `REVIEW.md` drives the decision, authoritative
174
- regardless of HEAD.
175
- 3. **HEAD bucket** — with no steering files in play, the last-commit bucket plus
176
- working-tree cleanliness selects New Feature / Grilling / Clean / Health
177
- check / Idle.
178
-
179
- Within layers 2 and 3 the HEAD subject further disambiguates states the
180
- filesystem alone cannot separate (e.g. inside the `.gtd/` lifecycle, HEAD
181
- `gtd: planning` vs `gtd: building` vs `gtd: package done`).
182
-
183
- ### Commit taxonomy
184
-
185
- `gtd` writes a single **flat** `gtd: <phase>` subject for every workflow commit.
186
- The complete set:
187
-
188
- `gtd: new task` · `gtd: grilling` · `gtd: grilled` · `gtd: planning` ·
189
- `gtd: building` · `gtd: errors` · `gtd: feedback` · `gtd: fixing` ·
190
- `gtd: package done` · `gtd: awaiting review` · `gtd: done` · `gtd: health-check`
191
- · `gtd: health-fix` · `gtd: reviewing` — plus the hand-made `gtd: transport`
192
- (see below).
193
-
194
- The last commit subject is bucketed two ways:
195
-
196
- - **Boundary** — a non-`gtd:` commit, or exactly `gtd: done`. Marks a cold
197
- start: no workflow in progress.
198
- - **Mid-phase** — any other `gtd: <phase>` subject. Identifies the exact phase
199
- of an in-progress workflow.
200
-
201
- ### Precedence ladder (first match wins)
202
-
203
- 0. **HEAD `gtd: transport`** → Transport.
204
- 1. **ERRORS.md present** → Escalate (human gate; STOP).
205
- 2. **FEEDBACK.md present** → non-empty → Fixing; **empty** (clean agentic review
206
- = approval) → Close package.
207
- 3. **HEALTH.md present** → Health Fixing (idle health-fix loop; no `.gtd`,
208
- REVIEW.md, or FEEDBACK.md).
209
- 4. **.gtd present** → build lifecycle, routed by tree + HEAD:
210
- - `.gtd` modified (package files added/edited) → Planning
211
- - code changes present → Testing
212
- - clean tree + HEAD `gtd: fixing` (no-op fixer) → Testing (re-test)
213
- - else clean, by HEAD: `gtd: planning` / `gtd: package done` → Building;
214
- `gtd: building` → Agentic Review (or Close package, if force-approved)
215
- 5. **REVIEW.md present** → review lifecycle, routed by committed-ness + tree:
216
- committed + clean → Done; committed + checkbox-only edits (only `[ ]`↔`[x]`
217
- flips in REVIEW.md) → Done; committed + non-checkbox pending edits → Accept
218
- Review; uncommitted → Await Review (commits REVIEW.md and auto-advances to
219
- Done). 5a. **HEAD `gtd: done` + `squash` enabled + squash base present + no
220
- unrelated code dirty** (a lone untracked `SQUASH_MSG.md` is allowed) →
221
- Squashing; unrelated code dirty → New Feature. 8a. **Green health check + ≥1
222
- `gtd: health-fix` + `squash` enabled** → Squashing (same agent-authored
223
- conventional-commits path as the feature-cycle squash — no hardcoded
224
- placeholder).
225
- 6. **Boundary HEAD + pending changes** (and no `.gtd`/REVIEW/FEEDBACK), or HEAD
226
- `gtd: new task` + clean tree (regenerate a lost seed) → New Feature.
227
- 7. **TODO.md present** → Grilling / Grilled.
228
- 8. **Boundary or `gtd: package done` HEAD + clean tree** → Clean (review the
229
- work), **Health check** (run `testCommand` when there is nothing to review —
230
- on any branch outside a process), or Idle (health check green, nothing to
231
- do).
232
-
233
- Anything matching no rule is corruption — `gtd` **hard-errors** rather than
234
- guess.
235
-
236
- ```mermaid
237
- flowchart TD
238
- Start([Run gtd]) --> P0{"HEAD = gtd: transport?"}
239
- P0 -->|yes| Transport["Transport — mixed-reset HEAD, re-derive"]:::edge
240
- Transport -.->|re-resolve| Start
241
- P0 -->|no| P1{"ERRORS.md?"}
242
- P1 -->|yes| Escalate["Escalate — STOP, human gate"]:::gate
243
- P1 -->|no| P2{"FEEDBACK.md?"}
244
- P2 -->|"empty = approval"| Close["Close package — rm pkg dir, gtd: package done"]:::edge
245
- P2 -->|"non-empty"| Fixing["Fixing — rm FEEDBACK, fixer agent"]:::agent
246
- P2 -->|absent| P2b{"HEALTH.md?"}
247
- P2b -->|"present"| HealthFix["Health Fixing — rm HEALTH.md, gtd: health-check, fixer agent (leaves edits uncommitted)"]:::agent
248
- HealthFix -.->|"next gtd run: dirty health HEAD → commit gtd: health-fix, re-resolve"| HealthCheck
249
- P2b -->|absent| P3{".gtd/?"}
250
- P3 -->|"modified"| Planning["Planning — gtd: planning"]:::agent
251
- P3 -->|"code dirty / resume / no-op fixer"| Testing["Testing — gtd: building, run tests"]:::edge
252
- P3 -->|"clean, HEAD planning/package done"| Building["Building — pick & build one package"]:::agent
253
- P3 -->|"clean, HEAD building"| Review["Agentic Review — write FEEDBACK.md"]:::agent
254
- P3 -->|absent| P4{"REVIEW.md?"}
255
- P4 -->|"committed + clean or checkbox-only edits"| Done["Done — rm REVIEW, gtd: done"]:::edge
256
- P4 -->|"committed + non-checkbox edits"| Accept["Accept Review — seed TODO, checkout, rm REVIEW"]:::edge
257
- P4 -->|"uncommitted"| Await["Await Review — commit gtd: awaiting review"]:::edge
258
- Await -.->|"re-resolve"| Done
259
- P4 -->|absent| P5{"boundary HEAD + dirty,<br/>or gtd: new task + clean?"}
260
- Done -->|"squash enabled"| Squashing["Squashing — agent authors conventional-commits message, reset --soft base, squash commit"]:::agent
261
- Done -->|"squash disabled"| Idle
262
- Squashing --> Idle["Idle — nothing to do (STOP)"]:::gate
263
- P5 -->|yes| NewFeature["New Feature — gtd: new task, revert, seed TODO"]:::edge
264
- P5 -->|no| P6{"TODO.md?"}
265
- P6 -->|"open markers"| GrillStop["Grilling — gtd: grilling, STOP for answers"]:::gate
266
- P6 -->|"dirty, no markers"| GrillIter["Grilling — gtd: grilling, agent iterates"]:::agent
267
- P6 -->|"clean, no markers"| Grilled["Grilled — gtd: grilled, decompose"]:::agent
268
- P6 -->|absent| P7{"clean + boundary/package-done HEAD,<br/>reviewable diff?"}
269
- P7 -->|yes| CleanState["Clean — write REVIEW.md"]:::agent
270
- P7 -->|"no (idle, outside a process)"| HealthCheck["Health check — run testCommand"]:::edge
271
- HealthCheck -->|"green, no health-fix"| Idle
272
- HealthCheck -->|"green + ≥1 health-fix, squash enabled"| Squashing
273
- HealthCheck -->|"red, below cap"| HealthMd["write HEALTH.md, gtd: health-check"]:::edge
274
- HealthMd -.->|"re-resolve"| HealthFix
275
- HealthCheck -->|"red, at cap"| ErrorsMd["write ERRORS.md, gtd: health-check"]:::edge
276
- ErrorsMd -.->|"re-resolve"| Escalate
277
- classDef edge fill:#1a4a6b,color:#fff
278
- classDef agent fill:#2d6a4f,color:#fff
279
- classDef gate fill:#7a3b1d,color:#fff
192
+ **Agent tail lines.** In plain-mode output, a prompt for the **agent** actor
193
+ ends with the pinned tail:
194
+
195
+ ```
196
+ Finish your turn by running `gtd step-agent`. Then run `gtd next` and follow
197
+ its output repeat this cycle as long as the output is addressed to you (the
198
+ agent); when it awaits the human, stop and hand off.
280
199
  ```
281
200
 
282
- > Blue = **edge-only** (the edge performs IO; no prompt rendered). Green =
283
- > **agent** (a prompt is emitted; the agent acts, then re-runs gtd). Brown =
284
- > **gate** (STOP for the human, or nothing to do).
201
+ The first sentence closes the current turn; the second closes the outer loop —
202
+ it is what lets a plain-text agent chain multiple iterations (e.g. successive
203
+ test/fix cycles) without an external driver, until a human gate is reached.
204
+ Human-actor prompts carry no tail. `--json` output never embeds the tail into
205
+ `prompt` either — the structured `actor` field (see JSON schemas below) carries
206
+ the same information: `"agent"` means another agent round, `"human"` means stop
207
+ and hand off.
208
+
209
+ ### `gtd status`
285
210
 
286
- ### Illegal combinations
211
+ Pure, read-only **dry-run prediction** — the same gather+resolve `gtd next`
212
+ runs, but reporting a prediction of the next turn rather than the actual prompt.
213
+ Performs no git mutation, no test run, no file write — guaranteed side-effect
214
+ free, including on a dirty tree.
287
215
 
288
- These never arise in normal flow; if seen, `gtd` hard-errors rather than
289
- guessing:
216
+ Prints four fields:
217
+
218
+ ```
219
+ State: grilling
220
+ Awaits: human
221
+ Predicted commit: gtd(human): grilling
222
+ Predicted state: grilling
223
+ ```
290
224
 
291
- - REVIEW.md + .gtd
292
- - REVIEW.md + TODO.md
293
- - FEEDBACK.md + REVIEW.md
294
- - FEEDBACK.md without .gtd
295
- - ERRORS.md + FEEDBACK.md
296
- - ERRORS.md without .gtd
297
- - HEALTH.md + .gtd (health check only runs from a bare idle tree)
298
- - HEALTH.md + REVIEW.md (same)
299
- - HEALTH.md + FEEDBACK.md (same)
300
- - HEALTH.md + ERRORS.md (escalation wins; HEALTH.md must not coexist)
225
+ - **State** the currently resolved state.
226
+ - **Awaits** the actor (`human` or `agent`) whose turn it is.
227
+ - **Predicted commit** — the subject `step`/`step-agent` would author next, or
228
+ `(none)` at a fixpoint (e.g. idle with nothing to do).
229
+ - **Predicted state** — the state that commit would land in.
301
230
 
302
- Legal coexistence: `.gtd` + TODO.md (plan kept alongside packages during
303
- **Planning** only — TODO.md is deleted at the first Building turn);
304
- FEEDBACK.md + `.gtd` (a fix during build).
231
+ `gtd status` takes no arguments extra positional args are rejected.
305
232
 
306
- ### Single writer, linear branch
233
+ ### `gtd review <target>`
307
234
 
308
- State is folded from **first-parent** history: gtd assumes a **single writer on
309
- a linear branch**. A merge commit at HEAD is unsupported it breaks the counter
310
- folds, the review base, and last-commit detection (documented, not handled).
235
+ A pure mutator that **anchors, then exits** it never prints a prompt itself.
236
+ Use it to start an ad-hoc human review against an explicit git ref or branch,
237
+ independent of the automatic review base the workflow otherwise computes.
311
238
 
312
- Distribute work by **sequential handoff** (one active machine at a time) over
313
- **rebase / fast-forward**, not by merging parallel branches. The primitive for
314
- carrying _uncommitted_ work across machines or branches is `gtd: transport`:
239
+ 1. Refuses on a dirty tree.
240
+ 2. Resolves `<target>` via merge-base semantics and computes the diff HEAD adds
241
+ over `merge-base(<target>, HEAD)`.
242
+ 3. Refuses if that diff is empty after filtering ("nothing to review").
243
+ 4. Authors exactly one commit: `gtd: reviewing <full-hash-of-the-base>`.
244
+ 5. Prints a short confirmation pointing at `gtd next` — it does **not** print
245
+ the review prompt itself.
315
246
 
316
247
  ```bash
317
- git add -A && git commit -m "gtd: transport" # on the source machine
318
- git push # then pull on the far side
248
+ gtd review main
249
+ # anchored review at <hash> — run `gtd next` to get the review prompt
250
+ gtd next --json
251
+ # {"actor":"agent", ...} — the review-record prompt scoped to that anchor
319
252
  ```
320
253
 
321
- There is **no `gtd transport` subcommand** — you make this commit by hand. The
322
- **Transport** state consumes it: on the far side, the next `gtd` run sees the
323
- `gtd: transport` HEAD, mixed-resets it (`git reset HEAD~1`) to drop the work
324
- back into the working tree uncommitted, and re-derives state from scratch. If
325
- the transport commit is the repository's root commit (no parent), `gtd` fails
326
- immediately with a clear error instead of looping.
327
-
328
- ## The 19 states
329
-
330
- Each state has a **condition** (when it wins), a deterministic **action**, the
331
- **commit(s)** it produces, and where it **advances**. States marked
332
- **auto-advance** re-run `gtd` themselves; **STOP** states hand control to a
333
- human; **edge-only** states render no prompt at all — the driver performs their
334
- action and re-resolves silently.
335
-
336
- | State | Kind | Wins when | Action & commit | Advances to |
337
- | ------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
338
- | **Transport** | edge-only, auto | HEAD `gtd: transport` (hand-made handoff commit) | mixed-reset HEAD (`git reset HEAD~1`), keep work in tree; **no commit** | re-derive from the restored tree |
339
- | **Escalate** | STOP | ERRORS.md present | none | held until the human deletes ERRORS.md |
340
- | **Fixing** | agent, auto | non-empty FEEDBACK.md present | inline FEEDBACK into the prompt, remove FEEDBACK.md; commit its removal `gtd: fixing` (FEEDBACK was committed by Testing) or `gtd: feedback` (uncommitted, written by Agentic Review) | fixer edits → Testing |
341
- | **Health Fixing** | agent, auto | HEALTH.md present (no `.gtd`, REVIEW.md, or FEEDBACK.md) | read HEALTH.md into the prompt, commit its removal `gtd: health-check` (HEALTH.md removed so next resolve re-enters `resolveCleanOrIdle`); fixer leaves edits **uncommitted** | fixer edits uncommitted → next `gtd` invocation commits them `gtd: health-fix` → Health check |
342
- | **Close package** | edge-only, auto | empty FEEDBACK.md present (clean review); also reached from Agentic Review force-approve | rm FEEDBACK.md, rm the first (finished) package dir (+ the now-empty `.gtd/`); commit `gtd: package done` | more packages → Building; `.gtd` gone → Clean |
343
- | **Planning** | agent, auto | `.gtd` present **and modified**; HEAD `gtd: grilled` or `gtd: planning` | commit the `.gtd/` changes `gtd: planning` | continue decomposing, else → Building |
344
- | **Testing** | edge-only, auto | `.gtd` present, no FEEDBACK/ERRORS, and a reason to test: code changes, a pending ERRORS.md deletion (human resume), or a clean tree under HEAD `gtd: fixing` (no-op fixer) | commit pending tree `gtd: building`, run `testCommand`; green → proceed; red → write FEEDBACK (below cap) or ERRORS (at cap), commit `gtd: errors`; if captured output is empty/whitespace, a sentinel string is written so the file is never empty (empty FEEDBACK remains reserved for agentic-review approval) | green → Agentic Review; FEEDBACK → Fixing; ERRORS → Escalate |
345
- | **Building** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: planning` or `gtd: package done` | if HEAD `gtd: planning` and TODO.md present, delete TODO.md and commit (prefix unchanged, fires once); select the first package, inline its tasks; agent leaves work **uncommitted** | Testing |
346
- | **Agentic Review** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: building` | reviewer writes FEEDBACK.md (empty = approval), uncommitted — **unless** force-approved (kill-switch off or review-fix threshold hit), which routes straight to Close package | empty FEEDBACK → Close package; non-empty → Fixing |
347
- | **Done** | edge-only, auto | REVIEW.md committed + clean tree, **or** committed + checkbox-only edits (only `- [ ]`→`- [x]` flips in REVIEW.md = approval) | rm REVIEW.md, commit `gtd: done` | Squashing (if enabled) or Idle |
348
- | **Squashing** | agent, auto | no steering files, HEAD `gtd: done` or green Health check with ≥1 `gtd: health-fix`, `squash` enabled, squash base present, no unrelated code dirty (a lone untracked `SQUASH_MSG.md` is allowed) | agent authors a conventional-commits message from the full `<base>..HEAD` diff, then runs `git reset --soft <base>` + `git commit` — collapses all intermediate `gtd: *` commits (including any interleaved non-gtd commits) into one; **gtd then STOPs** — post-squash review fires only on the next manual `gtd` run | Idle (STOP) |
349
- | **Accept Review** | edge-only, auto | REVIEW.md committed + pending **non-checkbox** edits (human annotated REVIEW.md with comments / edited code) | seed TODO.md from the changeset, `git checkout` to discard the code edits, rm REVIEW.md; **all uncommitted** | Grilling |
350
- | **Await Review** | edge-only, auto | REVIEW.md present and **uncommitted** (freshly written by Clean) | commit REVIEW.md `gtd: awaiting review` | Done (auto, same run) |
351
- | **New Feature** | edge-only, auto | boundary HEAD + pending changes (code and/or a new uncommitted TODO.md), **or** HEAD `gtd: new task` + clean tree (lost-seed regen) | commit the raw input verbatim `gtd: new task` (unless already there), `git revert --no-commit` it back to a clean baseline, seed TODO.md from that diff — revert + seed left **uncommitted** | Grilling |
352
- | **Grilling** | agent (iterate) / STOP (answers) | TODO.md present, not New Feature | commit pending edits `gtd: grilling`. Open-question markers present → STOP for the human to answer inline; no markers but dirty → grilling agent iterates | converge (no markers, clean tree) → Grilled |
353
- | **Grilled** | agent, auto | TODO.md present, no markers, clean tree | commit pending `gtd: grilled` | decompose into `.gtd/` → Planning |
354
- | **Clean** | agent | no steering files, clean tree, boundary or `gtd: package done` HEAD, and the review base yields a **non-empty** diff | compute the review base (three rules — see below); agent writes REVIEW.md **uncommitted** with `# Review: <short-hash>` heading, `<!-- base: <full-hash> -->` marker, and per-hunk `- [ ]` checkboxes (ticking them signals approval → Done) | Await Review |
355
- | **Health check** | edge-only, auto | no steering files, outside a process with no reviewable diff (any branch) — the `!reviewable` case from rule 8. Two entry points: (a) clean tree under a boundary or `gtd: package done` HEAD; (b) **dirty tree under a `gtd: health-check` or `gtd: health-fix` HEAD with `!pendingErrorsDeletion`** (the fixer's uncommitted edits — commits them `gtd: health-fix` and re-runs the health check within the same `gtd` invocation; NOT corruption). | run `testCommand` (entry point a); or commit pending edits `gtd: health-fix`, then run `testCommand` (entry point b). green + no prior `gtd: health-fix` → Idle (no commit); red below `fixAttemptCap` → write HEALTH.md, commit `gtd: health-check` → Health Fixing; red at cap → write ERRORS.md, commit `gtd: health-check` → Escalate; green + ≥1 `gtd: health-fix` → Squashing (if `squash`) or Idle | green → Idle or Squashing; red below cap → Health Fixing; red at cap → Escalate |
356
- | **Idle** | STOP | no steering files, clean tree, health check passed with no prior `gtd: health-fix` commits, and nothing to review | none (no commit — the health check edge terminates the driver loop directly) | — |
357
-
358
- Every prompt also embeds the current `git diff HEAD` (untracked files included)
359
- inline, plus the last commit subject and working-tree status, so the agent has
360
- full context.
361
-
362
- ### Review base — three rules
363
-
364
- The review base (the commit whose diff to HEAD forms the REVIEW.md) is chosen by
365
- three rules evaluated in priority order:
366
-
367
- 1. **Within a process, first review** — a `gtd: grilling` commit exists after
368
- the last `gtd: done` (or task start), but no `gtd: awaiting review` yet →
369
- base = first `gtd: grilling` of the current task cycle; `refDiff` spans the
370
- whole task.
371
- 2. **Within a process, incremental** — `gtd: awaiting review` also present in
372
- the current cycle (takes precedence over rule 1) → base = last
373
- `gtd: awaiting review`; `refDiff` spans only the post-review changes.
374
- 3. **Outside a process (any branch)** — no `gtd: grilling` after the last
375
- `gtd: done` → skip review; `reviewBase`/`refDiff` unset → Idle (the health
376
- check runs instead).
377
-
378
- In all cases, if the diff from the chosen base to HEAD is empty,
379
- `reviewBase`/`refDiff` are left unset and the machine settles in Idle.
380
-
381
- ## The fix loops & counter folds
382
-
383
- Three derived counters drive the budgeted loops. All are **folded in the
384
- machine** from flags on the `COMMIT[]` stream — never recomputed at the edge:
385
-
386
- - **`testFixCount`** — `gtd: errors` commits (test-fix attempts) since the
387
- **most recent of** {a package start (`gtd: planning` / `gtd: package done`), a
388
- `gtd: feedback` (start of a review-fix), or a commit that **removed
389
- ERRORS.md** (a human resume)}. So each test-fix sub-loop, each review-fix
390
- round, and every human resume starts a **fresh budget**.
391
- - **`reviewFixCount`** — `gtd: feedback` commits (review-fix rounds) since the
392
- most recent package start.
393
- - **`healthFixCount`** — `gtd: health-check` commits since the most recent
394
- commit that removed HEALTH.md (or the start of branch history if none). Reuses
395
- `fixAttemptCap` — no separate config key.
396
-
397
- ### Test-fix loop (`fixAttemptCap`, default 3)
398
-
399
- When Testing's run is red, it writes the captured output and commits
400
- `gtd: errors`, incrementing `testFixCount`. If the captured output is empty or
401
- whitespace-only (e.g. a command that exits non-zero with no output), a sentinel
402
- string is written instead — so FEEDBACK/ERRORS is never empty. Empty FEEDBACK
403
- remains reserved exclusively for Agentic Review's deliberate approval signal.
254
+ Errors (all exit 1, message on stderr):
404
255
 
405
- ```
406
- Building Testing(red) → Fixing → Testing(red) → … → Testing(green)
407
- │ │
408
- └── below cap: FEEDBACK.md, gtd: errors ───┘
409
- └── at/over the cap: ERRORS.md, gtd: errors → Escalate
410
- ```
256
+ - Missing target: `gtd review: missing target argument`
257
+ - Extra arguments:
258
+ `gtd review: too many arguments — expected one target, got: …`
259
+ - Unresolvable ref: `gtd review: cannot resolve ref '<target>': <error message>`
260
+ - Empty diff:
261
+ `gtd review: nothing to review (<target> diff is empty after filtering)`
411
262
 
412
- Below the cap, the failure goes to **FEEDBACK.md** and Fixing applies a fix. At
413
- or over the cap (`testFixCount >= fixAttemptCap`), it goes to **ERRORS.md**
414
- instead and the loop **stops** at Escalate. The human investigates, then deletes
415
- ERRORS.md — which **resets the fix-attempt budget** (the next run re-tests and
416
- grants a fresh `cap` attempts before escalating again). While ERRORS.md exists,
417
- every run resolves straight back to Escalate.
263
+ ### `gtd format <file>`
418
264
 
419
- ### Health-fix loop (`fixAttemptCap`, `squash` no new config)
265
+ Unchanged from v1: formats a markdown file in place with a bundled prettier
266
+ (`parser: "markdown"`, `printWidth: 80`, `proseWrap: "always"`), ignoring the
267
+ host repo's own `.prettierrc` so `.gtd/TODO.md`/`.gtd/REVIEW.md` stay
268
+ consistently formatted regardless of the host project's toolchain. Rejects
269
+ `--json` (exit 1, `gtd format does not accept --json`) — it is a plain file
270
+ operation, not a v2 state command.
420
271
 
421
- Outside a process (any branch), when there is no reviewable diff and no steering
422
- files, `gtd` runs `testCommand` instead of stopping. This reuses `fixAttemptCap`
423
- (default 3) and `squash` — no new config keys are introduced.
272
+ Errors (all exit 1, message on stderr):
424
273
 
274
+ - Missing path: `gtd format: missing file path argument`
275
+ - Extra arguments: `gtd format: too many arguments — expected one path, got: …`
276
+ - Non-markdown file:
277
+ `gtd format: <file> is not a markdown file (expected .md or .markdown)`
278
+ - File not found: `gtd: skipped formatting <file>: not found`
279
+
280
+ ## JSON schemas
281
+
282
+ Pass `--json` to `step`, `step-agent`, `next`, or `status` for machine-readable
283
+ single-line JSON output instead of plain text.
284
+
285
+ **`step` / `step-agent`** — `{state, actions, commits}`:
286
+
287
+ ```json
288
+ {
289
+ "state": "grilled",
290
+ "actions": ["capture the human turn as \"gtd(human): grilling\""],
291
+ "commits": ["gtd(human): grilling", "gtd: grilled"]
292
+ }
293
+ ```
294
+
295
+ - `state` — the final resolved state after the fixpoint loop settled.
296
+ - `actions` — human-readable descriptions of every edge action this invocation
297
+ performed, oldest→newest.
298
+ - `commits` — every commit subject this invocation authored, oldest→newest.
299
+
300
+ **`next`** — `{state, actor, pending, prompt}`:
301
+
302
+ ```json
303
+ {
304
+ "state": "building",
305
+ "actor": "agent",
306
+ "pending": false,
307
+ "prompt": "..."
308
+ }
425
309
  ```
426
- Idle path → Health check(red) → Health Fixing → [fixer edits, uncommitted]
427
- │ │
428
- next gtd run: commit gtd: health-fix
429
- │ │
430
- │ Health check(red)
431
- │ │
432
- │ Health check(green)
433
- │ │
434
- └── below cap: HEALTH.md, gtd: health-check └── green + ≥1 health-fix → Squashing (if squash enabled) → Idle
435
- └── at/over the cap: ERRORS.md, gtd: health-check Escalate
310
+
311
+ - `state` — the resolved state.
312
+ - `actor` — `"human"` or `"agent"`: who owns the next move. This is the single
313
+ loop-driver signal: `"agent"` means proceed with another round — act on
314
+ `prompt` when present, then run `gtd step-agent`; at an agent-driven pending
315
+ checkpoint (`prompt` is `null`, nothing to act on) just run `gtd step-agent`.
316
+ `"human"` means halt and hand off (a human rest, whose prompt body already
317
+ tells the human what to do, or a human-driven pending checkpoint resumed by
318
+ `gtd step`).
319
+ - `pending` `true` at a mid-chain HEAD (no prompt yet — resume with a mutator
320
+ first); `false` at a genuine rest.
321
+ - `prompt` — the full prompt markdown when `pending` is `false`, else `null`.
322
+
323
+ **`status`** — `{state, actor, predictedCommit, predictedState}`:
324
+
325
+ ```json
326
+ {
327
+ "state": "grilling",
328
+ "actor": "human",
329
+ "predictedCommit": "gtd(human): grilling",
330
+ "predictedState": "grilling"
331
+ }
436
332
  ```
437
333
 
438
- - **green, no prior `gtd: health-fix`** Idle immediately (no commit).
439
- - **red, below `fixAttemptCap`** write test output to HEALTH.md, commit
440
- `gtd: health-check` → **Health Fixing** agent fixes the code and leaves its
441
- edits **uncommitted**. The next `gtd` invocation detects the dirty tree under
442
- the `gtd: health-check` HEAD, commits the fixer's edits as `gtd: health-fix`
443
- (an edge-only `health-check` state with a `commitPending` action), and
444
- immediately re-runs the health check within that same invocation.
445
- - **red, at or over `fixAttemptCap`** → write test output to ERRORS.md, commit
446
- `gtd: health-check` → **Escalate** (human gate). Delete ERRORS.md to reset the
447
- budget and resume.
448
- - **green, ≥1 `gtd: health-fix` present** → health-fix cycle converged: if
449
- `squash` is enabled → **Squashing** (squash base = parent of the first
450
- `gtd: health-check` of the current run); otherwise → Idle (no commit).
451
-
452
- ### Review-fix loop & agentic review (`reviewThreshold`, default 3)
453
-
454
- After a green test run, **Agentic Review** reviews the package's accumulated
455
- diff against its task specs and **always writes FEEDBACK.md**:
334
+ `predictedCommit` is `null` when the next invocation would author nothing (e.g.
335
+ idle with a green health check).
336
+
337
+ **Error envelope** every command, in `--json` mode, reports failures inside
338
+ the JSON object rather than as unstructured text, and still exits 1:
456
339
 
340
+ ```json
341
+ { "state": "error", "prompt": "<message>" }
457
342
  ```
458
- Testing(green) → Agentic Review → empty FEEDBACK → Close package → next package
459
-
460
- └─ findings Fixing(gtd: feedback) Testing Agentic Review
343
+
344
+ There is no auto-advance flag anywhere in the wire format — `actor` replaces it.
345
+ The caller decides whether to keep looping based on `actor` (halt on `"human"`)
346
+ and `pending` (re-run `step`/`step-agent` first when `true`), not on a boolean
347
+ auto-advance flag.
348
+
349
+ ## The reference loop driver
350
+
351
+ A minimal bash implementation of the pinned two-beat protocol, driving an agent
352
+ CLI (e.g. `claude -p`) against `gtd --json` output. This is the authoritative
353
+ reference for what a loop driver must do; keep any other implementation
354
+ (including `skills/loop/SKILL.md`) consistent with it rather than editing both
355
+ independently.
356
+
357
+ ```bash
358
+ #!/usr/bin/env bash
359
+ set -euo pipefail
360
+
361
+ while true; do
362
+ # 1. Advance the machine's own agent-owned bookkeeping to a fixpoint.
363
+ gtd step-agent --json >/dev/null || true
364
+
365
+ # 2. Ask who's up next. `actor` is the single "proceed" signal.
366
+ next="$(gtd next --json)"
367
+ actor="$(jq -r .actor <<<"$next")"
368
+ prompt="$(jq -r .prompt <<<"$next")"
369
+
370
+ if [[ "$actor" != "agent" ]]; then
371
+ echo "Halting — the human owns the next move."
372
+ break
373
+ fi
374
+
375
+ if [[ "$prompt" == "null" ]]; then
376
+ # Agent-driven pending checkpoint: nothing to act on — loop back to
377
+ # step 1, whose `gtd step-agent` resumes the mid-chain bookkeeping.
378
+ continue
379
+ fi
380
+
381
+ # Agent's turn: feed the prompt to the agent, then let it finish with
382
+ # `gtd step-agent` itself (the prompt's tail instructs it to).
383
+ claude -p "$prompt" --dangerously-skip-permissions
384
+ done
461
385
  ```
462
386
 
463
- An **empty FEEDBACK.md is approval** Close package removes the finished
464
- package directory and commits `gtd: package done`. Findings route to Fixing
465
- (committed `gtd: feedback`, incrementing `reviewFixCount`), which loops back
466
- through the test gate and re-reviews. Once `reviewFixCount >= reviewThreshold`,
467
- Agentic Review **force-approves** (skips the review, closes the package
468
- directly) so a package can never review-loop forever. Setting
469
- **`agenticReview: false`** is a kill-switch: every package force-approves
470
- immediately and the branch proceeds straight to human review.
471
-
472
- ### Per-package close
473
-
474
- Close package operates on **one** package at a time: it deletes the first
475
- (finished) numbered directory under `.gtd/` — plus the now-empty `.gtd/` itself
476
- if it was the last — and commits `gtd: package done`, which sends Building to
477
- the next package (or Clean once `.gtd/` is gone). Each package thus runs the
478
- full
479
- `Building Testing Agentic Review → (Fixing → Testing → Agentic Review)* → Close`
480
- loop before the next one starts.
481
-
482
- ## A typical feature
483
-
484
- 1. **Capture.** Leave a sketch in `TODO.md` (or just some pending code changes),
485
- then run `gtd`. **New Feature** commits the raw input `gtd: new task`,
486
- reverts it back to a clean baseline, and seeds an uncommitted `TODO.md` from
487
- the diff.
488
- 2. **Grill.** Run `gtd` — the **Grilling** agent (planning model) develops the
489
- plan, appends open questions each marked with a `<!-- user answers here -->`
490
- line, and leaves `TODO.md` uncommitted; the edge commits `gtd: grilling`.
491
- While any marker is present, gtd **STOPs** for you.
492
- 3. **Answer.** Open `TODO.md`, replace each `<!-- user answers here -->` with
493
- your answer, and run `gtd` again. The agent integrates answers, moves them to
494
- `## Resolved`, and raises fresh questions — repeat until none remain (it
495
- writes `no open questions run gtd to plan` with no markers).
496
- 4. **Converge.** A clean tree with no markers resolves to **Grilled**
497
- (`gtd: grilled`), then **Planning** decomposes `TODO.md` into ordered `.gtd/`
498
- work packages (`gtd: planning`).
499
- 5. **Build.** Run `gtd` **Building** first deletes `TODO.md` (when HEAD is
500
- `gtd: planning` and it is still present, committed under the same
501
- `gtd: planning` prefix fires once). It then names the single next package
502
- and inlines its task files; the agent spawns one parallel subagent per task
503
- (execution model + TDD) and leaves the work **uncommitted**. The next run is
504
- **Testing**: the edge commits `gtd: building`, then runs `testCommand`.
505
- 6. **Review each package.** On green, **Agentic Review** writes FEEDBACK.md.
506
- Empty → **Close package** (`gtd: package done`) and on to the next package;
507
- findings **Fixing** back through the test gate. A red test run drives the
508
- test-fix loop until green or Escalate.
509
- 7. **Human review.** When `.gtd/` is gone, **Clean** writes a `REVIEW.md` for
510
- the diff since the review base (uncommitted); **Await Review** (edge-only)
511
- commits it `gtd: awaiting review` and auto-advances to Done in the same run.
512
- 8. **Approve or revise.** Re-run `gtd` with **no** changes to approve → **Done**
513
- (`gtd: done`) → **Squashing** → **Idle**. The Squashing agent authors a
514
- conventional-commits message from the full process diff and squashes all
515
- intermediate `gtd: *` commits into one with `git reset --soft <base>` +
516
- `git commit`, then **gtd STOPs**. The base is the parent of the current
517
- cycle's start marker **nearest to HEAD** (the last `gtd: new task`; for
518
- legacy cycles the last contiguous `gtd: grilling` run), and on a feature
519
- branch it never reaches below the merge-base with the default branch — stray
520
- markers left behind by older squashes can never drag the squash into
521
- previously shipped features. Post-squash review does not fire automatically —
522
- it fires only on the next manual `gtd` run (when the squash commit is the
523
- boundary HEAD and a reviewable diff exists). Squashing fires when the tree
524
- has no unrelated code dirty a lone untracked `SQUASH_MSG.md` is tolerated
525
- and deleted before the squash commit. If unrelated code is dirty at
526
- `gtd: done`, gtd routes to **New Feature** instead. Set `squash: false` in
527
- `.gtdrc` to skip squashing and go straight to Idle. Checking off REVIEW.md
528
- checkboxes (`- [ ]` `- [x]`) also counts as approval and routes to **Done**
529
- — they are navigation aids, not feedback. Only **non-checkbox** edits (code
530
- changes, inline comments, textual annotations in REVIEW.md) trigger **Accept
531
- Review**, which seeds a fresh `TODO.md` from your feedback, discards your
532
- code edits, removes `REVIEW.md`, and re-enters Grilling — the loop starts
533
- over.
387
+ The agent is expected to run `gtd step-agent` itself once it finishes acting on
388
+ the prompt (the plain-mode tail says exactly this) the driver's own
389
+ `step-agent` calls exist to advance any bookkeeping the agent doesn't own
390
+ (routing commits, test runs) between agent turns.
391
+
392
+ The loop halts on `actor: "human"` alone: a human rest (`pending: false`, the
393
+ prompt body addresses the human) or a human-driven pending checkpoint
394
+ (`pending: true`, resumed by the human's own `gtd step`). Everything the agent
395
+ side can drive — agent rests and agent-driven checkpoints — reports
396
+ `actor: "agent"`, so multiple agent turns and commits (e.g. successive test/fix
397
+ cycles, a force-approved package close) chain without human involvement until an
398
+ actual human gate is hit.
399
+
400
+ ## States & subjects overview
401
+
402
+ `resolve()` lands on exactly one of **16 states**: `grilling`, `grilled`,
403
+ `planning`, `building`, `testing`, `fixing`, `escalate`, `agentic-review`,
404
+ `close-package`, `review`, `await-review`, `done`, `squashing`, `idle`,
405
+ `health-check`, `health-fixing`. Each state has a fixed awaited actor (see
406
+ `awaitedActor` in `src/Machine.ts`): `idle`, `escalate`, and `await-review`
407
+ await the **human**; every other state awaits the **agent**.
408
+
409
+ For the full precedence ladder, illegal combinations, and the counter folds that
410
+ drive the fix loops, see [STATES.md](STATES.md) this section is a summary.
411
+
412
+ ### Turn commits `gtd(<actor>): <gate>`
413
+
414
+ Authored by `gtd step`/`gtd step-agent` as the first commit of a fresh chain.
415
+ The closed set of gates:
416
+
417
+ | Gate | Authored by |
418
+ | ---------------- | ------------------------------------------------------------------ |
419
+ | `grilling` | human (answers) / agent (plan iteration) |
420
+ | `grilled` | agent (converged, ready to decompose) |
421
+ | `building` | agent (package work, or human feedback while agent is out of turn) |
422
+ | `fixing` | agent (test-fix or review-fix round) |
423
+ | `agentic-review` | agent (writes .gtd/FEEDBACK.md verdict) |
424
+ | `review` | agent (writes .gtd/REVIEW.md) / human (approves or gives feedback) |
425
+ | `squashing` | agent (overwrites .gtd/SQUASH_MSG.md) |
426
+ | `health-fixing` | agent (idle health-check repair) |
427
+ | `escalate` | human (deletes .gtd/ERRORS.md to resume) |
428
+
429
+ ### Routing commits `gtd: <phase>`
430
+
431
+ Bookkeeping the machine authors itself between turns, never a turn a human or
432
+ agent "wins": `gtd: grilled`, `gtd: planning`, `gtd: tests green`,
433
+ `gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
434
+ `gtd: review feedback`, `gtd: done`, `gtd: squash template`,
435
+ `gtd: reviewing <hash>` (parameterized, from `gtd review`), `gtd: health-check`,
436
+ `gtd: health-fix`.
437
+
438
+ Everything else any non-`gtd` subject, and any `gtd: *` subject outside this
439
+ closed set is a **boundary commit**: inert as far as the machine's grammar is
440
+ concerned. See [Upgrading from v1](#upgrading-from-v1-breaking-change) for why
441
+ this matters on upgrade.
442
+
443
+ ## Workflow walkthroughs
444
+
445
+ ### Grilling
446
+
447
+ A dirty tree at a boundary HEAD (a fresh idea, sketched in a file or just left
448
+ as pending code) is captured in **one** human turn: `gtd step` commits
449
+ everything pending as `gtd(human): grilling` nothing is reverted or seeded,
450
+ the captured files stay in history. `gtd next` hands the agent that turn's diff;
451
+ the agent develops `.gtd/TODO.md` into a concrete plan **in one turn**,
452
+ proposing a **suggested default** for every open question, and leaves
453
+ `.gtd/TODO.md` uncommitted for `gtd(agent): grilling`.
454
+
455
+ There are no markers to answer the human either:
456
+
457
+ - **Accepts the suggested defaults**: runs a clean `gtd step` at the answer
458
+ gate. An empty `gtd(human): grilling` turn plus routing `gtd: grilled` lands
459
+ automatically, and `gtd next` emits the decompose prompt.
460
+ - **Edits `.gtd/TODO.md`** with real answers, then runs `gtd step`, which
461
+ captures the edit as a fresh `gtd(human): grilling` turn and hands it back to
462
+ the agent for another round.
463
+
464
+ ### Build lifecycle: budgets
465
+
466
+ Once decomposed, `.gtd/` holds ordered work packages. `gtd next` at
467
+ `gtd: planning`/`gtd: package done` selects the lowest-numbered remaining
468
+ package and inlines only its task files. The agent builds it and leaves the work
469
+ **uncommitted**; the next invocation's edge action commits it (the
470
+ `gtd(agent): building` turn commit) and runs `testCommand`.
471
+
472
+ - **Green** → Agentic Review.
473
+ - **Red, below `fixAttemptCap`** (default 3) → write findings, commit
474
+ `gtd: errors`, rest at **Fixing** for the agent.
475
+ - **Red, at/over the cap** → write `.gtd/ERRORS.md` instead, commit
476
+ `gtd: errors`, rest at **Escalate** — a human gate. Deleting `.gtd/ERRORS.md`
477
+ and landing that deletion as `gtd(human): escalate` resets the budget and
478
+ re-tests from zero in the same invocation.
479
+
480
+ ### Agentic review
481
+
482
+ A green test run always rests at **Agentic Review**: the agent reviews the
483
+ package's accumulated diff against its task specs and writes `.gtd/FEEDBACK.md`.
484
+ An **empty** `.gtd/FEEDBACK.md` is the approval signal — the same
485
+ `gtd(agent): agentic-review` turn closes the package (`gtd: package done`,
486
+ removing `.gtd/FEEDBACK.md` and the finished package directory) in one
487
+ invocation. Non-empty findings rest for the fixing prompt; fixing loops back
488
+ through the test gate and re-reviews. Once `reviewFixCount >= reviewThreshold`
489
+ (default 3) within a package, Agentic Review **force-approves** without ever
490
+ writing `.gtd/FEEDBACK.md` — so a package can never review-loop forever. The
491
+ findings round that crosses the threshold still gets its fixing round; the
492
+ force-approve close then fires at the next green re-test instead of another
493
+ review. (Any agentic-review turn that touches `.gtd/FEEDBACK.md` counts toward
494
+ the threshold — including the approval write itself; an approval that crosses
495
+ the threshold simply closes the package as usual.) Setting
496
+ `agenticReview: false` force-approves every package immediately.
497
+
498
+ A **do-nothing agent invocation** — `gtd step-agent` on a clean tree at ANY
499
+ agent-awaited rest whose move is a file artifact (`grilling`, `grilled`,
500
+ `building`, `fixing`, `agentic-review`, `review`, and `squashing` while
501
+ `.gtd/SQUASH_MSG.md` still holds the unmodified template) — is inert: zero
502
+ commits, no state consumed; `gtd next` re-emits the same prompt. This is
503
+ load-bearing for the loop protocol, whose every iteration opens with
504
+ `gtd step-agent` before the agent has acted: without the guard that opening beat
505
+ would author junk empty turns — and worse, consume workflow state (an empty
506
+ decompose turn would delete `.gtd/TODO.md` with no packages written; an empty
507
+ squashing turn would squash the cycle under the placeholder template). The same
508
+ guards hold at the classification layer for histories that already carry such
509
+ turns: a `gtd(agent): grilled` HEAD only routes to `gtd: planning` when packages
510
+ exist, a `gtd(agent): review` HEAD only routes to `gtd: awaiting review` when
511
+ `.gtd/REVIEW.md` exists, and a squashing turn only squashes once the template
512
+ has been overwritten. The one deliberate exception is `health-fixing`, whose
513
+ empty turn is meaningful (the failure may have been environmental — the machine
514
+ removes `.gtd/HEALTH.md` and re-tests). Human gates are unaffected: an empty
515
+ **human** turn stays a signal (accept-defaults at grilling, clean approval at
516
+ review).
517
+
518
+ ### Human review gate
519
+
520
+ Once `.gtd/` is fully closed, the machine writes `.gtd/REVIEW.md` and rests at
521
+ **await-review**, awaiting the human. Approval is any of:
522
+
523
+ - A **clean** `gtd step` (nothing edited) — an empty `gtd(human): review` turn
524
+ plus routing `gtd: done`.
525
+ - Flipping only `- [ ]` → `- [x]` checkboxes in `.gtd/REVIEW.md` — checkbox-only
526
+ edits are also treated as clean approval.
527
+
528
+ Any **substantive** edit — to `.gtd/REVIEW.md` prose, or to the reviewed code
529
+ itself — is feedback: `gtd(human): review` plus routing `gtd: review feedback`,
530
+ `.gtd/REVIEW.md` removed, and `gtd next` re-emits a grilling prompt to the agent
531
+ that inlines the human's finding.
532
+
533
+ ### Squash
534
+
535
+ With `squash: true` (the default), `gtd: done` is **not** a rest — the same
536
+ chain continues straight to `gtd: squash template`, writing and committing a
537
+ `.gtd/SQUASH_MSG.md` template. `gtd next` then emits the squashing prompt: the
538
+ agent overwrites `.gtd/SQUASH_MSG.md` with a real conventional-commits message
539
+ (drawing on grilling-round decisions from history) and finishes its turn.
540
+ `gtd step-agent` then performs the squash itself: `git reset --soft <base>` +
541
+ `git commit`, collapsing every intermediate `gtd: *` commit of the cycle into
542
+ one — including any review-feedback detours: the squash base is the cycle's
543
+ ORIGINAL start (the first grilling run since the previous `gtd: done` boundary,
544
+ or the `gtd: reviewing <hash>` anchor for an ad-hoc review cycle), not the most
545
+ recent re-grilling round — the collapse folds the whole cycle into one, using
546
+ the overwritten message's content verbatim (turn position, not message content,
547
+ triggers the squash). With `squash: false`, `gtd: done` is the resting boundary
548
+ and no template is ever written.
549
+
550
+ ### Health check
551
+
552
+ Outside any process (idle, nothing to review, no steering files), `gtd step`
553
+ runs `testCommand` as a health check rather than settling immediately. Green
554
+ settles idle with zero commits. Red below `fixAttemptCap` writes
555
+ `.gtd/HEALTH.md` and rests at **Health Fixing** for the agent; the fixer's own
556
+ turn (`gtd(agent): health-fixing`) removes `.gtd/HEALTH.md` and re-tests in the
557
+ same chain — a green re-test continues to squash (if enabled) or idle; red
558
+ repeats the health-fix loop; red at the cap writes `.gtd/ERRORS.md` and
559
+ escalates.
560
+
561
+ ### Escalate / budget reset
562
+
563
+ `.gtd/ERRORS.md` present is always a human gate, regardless of which loop wrote
564
+ it (test-fix or health-fix). Deleting `.gtd/ERRORS.md` and running `gtd step`
565
+ records the deletion as the human's `gtd(human): escalate` turn, which
566
+ **immediately re-tests in the same invocation** — this resets the relevant
567
+ fix-attempt budget to zero.
568
+
569
+ ## States & subjects: overview table
570
+
571
+ | State | Awaits | Turn/routing subject at rest |
572
+ | ---------------- | -------------- | ---------------------------------------------------------------- |
573
+ | `grilling` | human or agent | `gtd(human): grilling` / `gtd(agent): grilling` |
574
+ | `grilled` | agent | `gtd: grilled` |
575
+ | `planning` | agent | `.gtd/` modified |
576
+ | `building` | agent | `gtd: planning` / `gtd: package done` |
577
+ | `testing` | — (edge-only) | mid-chain only |
578
+ | `fixing` | agent | `gtd: errors` |
579
+ | `escalate` | human | `.gtd/ERRORS.md` present |
580
+ | `agentic-review` | agent | `gtd: tests green` |
581
+ | `close-package` | — (edge-only) | mid-chain only |
582
+ | `review` | agent | `gtd: package done` (no more packages) / `gtd: reviewing <hash>` |
583
+ | `await-review` | human | `gtd: awaiting review` |
584
+ | `done` | — (edge-only) | `gtd: done` |
585
+ | `squashing` | agent | `gtd: squash template` |
586
+ | `idle` | human | no steering files, green health check |
587
+ | `health-check` | — (edge-only) | mid-chain only |
588
+ | `health-fixing` | agent | `.gtd/HEALTH.md` present |
589
+
590
+ See [STATES.md](STATES.md) for the full precedence ladder, the counter folds,
591
+ and every illegal steering-file combination.
534
592
 
535
593
  ## Configuration
536
594
 
@@ -548,37 +606,34 @@ built-in defaults apply. Supported filenames (searched in this order):
548
606
  ### Schema
549
607
 
550
608
  - **`testCommand`** (string, default `npm run test`) — the command the edge runs
551
- in the Testing state to verify a built package, and in the Health check state
552
- on the default-branch idle path.
609
+ after a build turn, and on the idle health-check path.
553
610
  - **`fixAttemptCap`** (non-negative integer, default `3`) — the test-fix budget:
554
611
  how many `gtd: errors` attempts are allowed per sub-loop before the failure is
555
- escalated to ERRORS.md (Escalate). `0` disables the cap (escalates immediately
556
- on the first red run). Also reused as the health-fix budget (no separate
557
- config key).
612
+ escalated to `.gtd/ERRORS.md` (Escalate). `0` disables the cap (escalates
613
+ immediately on the first red run). Also reused as the health-fix budget no
614
+ separate config key.
558
615
  - **`reviewThreshold`** (integer ≥ 1, default `3`) — the review-fix budget: how
559
- many `gtd: feedback` rounds are allowed per package before Agentic Review
560
- force-approves.
616
+ many agentic-review findings rounds are allowed per package before Agentic
617
+ Review force-approves.
561
618
  - **`agenticReview`** (boolean, default `true`) — kill-switch for the
562
- per-package Agentic Review gate. Set to `false` to skip agentic review
563
- entirely; every package force-approves and the branch proceeds directly to
564
- human review.
565
- - **`squash`** (boolean, default `true`) after `gtd: done`, collapse all
566
- intermediate `gtd: *` commits into a single conventional-commits commit via
567
- `git reset --soft <base>` + `git commit`. Set `false` to keep the granular
568
- history.
619
+ per-package Agentic Review gate. Set `false` to force-approve every package
620
+ and proceed directly to human review.
621
+ - **`squash`** (boolean, default `true`) — after `gtd: done`, collapse the
622
+ cycle's `gtd: *` commits into a single conventional-commits commit. Set
623
+ `false` to keep the granular history.
569
624
  - **`models`** — model selection for the subagent-spawning states:
570
625
  - `planning` — high-reasoning tier (default `claude-opus-4-8`), used by
571
- `decompose`, `grilling`, `agentic-review`, and `clean`.
626
+ `decompose` (the `grilled`/`planning` states), `grilling`, `agentic-review`,
627
+ and `clean` (the `review`/`squashing` states).
572
628
  - `execution` — everyday tier (default `claude-sonnet-4-8`), used by
573
629
  `building` and `fixing`.
574
- - `states.*` — per-state overrides keyed by the six agent states: `decompose`
575
- (shared by the Grilled and Planning states), `grilling`, `building`,
576
- `fixing`, `agentic-review`, `clean`. Unknown `states` keys are **rejected**.
577
- - **`$schema`** (string, optional) — a recognized key that is **stripped before
578
- validation**, so it never counts as an unknown key. Point it at the published
579
- schema to get schema-backed autocompletion and inline docs in your editor. A
580
- `schema.json` is generated from the config schema at build time and ships with
581
- the package (and is published/committed on release).
630
+ - `states.*` — per-state overrides keyed by `decompose`, `grilling`,
631
+ `building`, `fixing`, `agentic-review`, `clean`. Unknown `states` keys are
632
+ **rejected**.
633
+ - **`$schema`** (string, optional) — stripped before validation, so it never
634
+ counts as an unknown key. Point it at the published schema for editor-backed
635
+ autocompletion. A `schema.json` is generated from the config schema at build
636
+ time and ships with the package.
582
637
 
583
638
  ### Validation and errors
584
639
 
@@ -586,50 +641,38 @@ If a config file fails to load or is invalid, gtd **exits with code 1** and
586
641
  writes a human-readable error to **stderr** (never stdout):
587
642
 
588
643
  - **Parse errors** (malformed YAML/JSON) — message includes the offending
589
- filename, e.g. `gtd: /path/to/.gtdrc: unexpected token`.
644
+ filename.
590
645
  - **Non-object top-level** — a YAML list or `null` at the root is rejected with
591
646
  the filename in the message.
592
647
  - **Schema violations** — unknown keys or out-of-range values emit
593
- `Invalid gtd config: <field>: <reason>`. The message is concise and does not
594
- dump the full type tree.
648
+ `Invalid gtd config: <field>: <reason>`.
595
649
  - **Missing test binary** — if `testCommand` names an executable that cannot be
596
- found (`ENOENT`), gtd exits with code 1 and writes
597
- `gtd: test command not found: <command>` to **stderr**. No stack trace is
598
- emitted to stdout. A non-zero test exit is _not_ an error — it drives the
599
- normal red-path (FEEDBACK → Fixing).
650
+ found (`ENOENT`), gtd exits 1 with `gtd: test command not found: <command>` on
651
+ stderr. A non-zero test _exit code_ is not an error it drives the normal red
652
+ path.
600
653
 
601
654
  ### Lookup and precedence
602
655
 
603
656
  gtd walks from the current working directory **up to your home directory** (or
604
657
  to the filesystem root when cwd is outside home), collecting every `.gtdrc` it
605
658
  finds along the way. All found levels are **deep-merged**, with the **innermost
606
- (cwd) config winning** on conflicts.
607
-
608
- This makes the worktree-parent case easy: drop a single `.gtdrc` in a shared
609
- parent directory and it cascades to **all** checkouts/worktrees beneath it,
610
- while any individual checkout can still override settings with its own `.gtdrc`.
659
+ (cwd) config winning** on conflicts — so a shared `.gtdrc` in a worktree-parent
660
+ directory cascades to every checkout beneath it, while any individual checkout
661
+ can still override settings with its own `.gtdrc`.
611
662
 
612
663
  ### Auto-init
613
664
 
614
- On every run, if the cwd→root walk finds **no** config anywhere, gtd creates and
615
- commits a starter config at the **git root**: a `.gtdrc.json` containing only a
616
- `$schema` link:
617
-
618
- ```json
619
- {
620
- "$schema": "https://raw.githubusercontent.com/pmelab/gtd/main/schema.json"
621
- }
622
- ```
623
-
624
- It is committed as `chore: add .gtdrc.json`. This wires up editor autocompletion
625
- out of the box; add any settings below the `$schema` line to override the
626
- defaults.
627
-
628
- Auto-init is skipped when HEAD is a `gtd: transport` commit: transport is a
629
- consume-only handoff HEAD (mixed-reset in the Transport pre-pass), so committing
630
- a config stub on top of it would displace the transport commit — and, when it is
631
- the repository root, silently mask the "cannot reset transport commit" error.
632
- The stub is created on a later run, once the transport HEAD has been consumed.
665
+ On every **state command** (`step`, `step-agent`, `next`, `status`, `review`)
666
+ that has passed the repo-root guard, if the cwd→root walk finds **no** config
667
+ anywhere, gtd creates and commits a starter `.gtdrc.json` at the repository root
668
+ containing only a `$schema` link. Auto-init never runs for `--version`/`--help`,
669
+ `format`, bare/unknown commands, or an invocation refused by the repo-root guard
670
+ — those perform no repository mutation of any kind. On a repo with no commits
671
+ yet, or whose HEAD is a plain (non-`gtd:`) commit, the stub is committed as its
672
+ own `chore: add .gtdrc.json`. If HEAD is already a `gtd:`-owned commit
673
+ (mid-workflow), the stub is instead **amended into HEAD** — stacking a fresh
674
+ boundary commit there would produce an unrecognized HEAD most workflow states
675
+ can't resolve past.
633
676
 
634
677
  ### Example
635
678
 
@@ -648,14 +691,32 @@ models:
648
691
  building: claude-sonnet-4-8
649
692
  ```
650
693
 
651
- ## Build orchestration
694
+ ## Repository requirements
695
+
696
+ - **Single writer, linear branch.** State is folded from **first-parent**
697
+ history only. A merge commit at HEAD is unsupported (documented, not handled)
698
+ — it degrades gracefully on the default branch rather than crashing, but do
699
+ not rely on merge commits mid-cycle.
700
+ - **Test/build artifacts must be gitignored.** This is **load-bearing**, not a
701
+ style preference: every fixpoint hop in `gtd step`/`gtd step-agent` detects
702
+ "clean" via `git status --porcelain`, which silently omits anything matched by
703
+ `.gitignore`. If your `testCommand` (or the build it triggers) writes
704
+ tracked-but-untracked output — a `dist/`, a coverage report, a log file — into
705
+ the working tree, the tree never goes clean after a green test run, and the
706
+ fixpoint loop cannot converge: it will either loop forever re-detecting a
707
+ "dirty" boundary or misclassify build output as the human's next feature
708
+ capture. Gitignore every path your test/build toolchain writes before wiring
709
+ gtd into a repo.
710
+ - **Repository root invocation.** Every subcommand except `--help`/`--version`
711
+ must run from the git repository root — steering files and diffs are resolved
712
+ against the process cwd.
652
713
 
653
- When a plan is finalized, gtd enters build mode.
714
+ ## Build orchestration
654
715
 
655
716
  ### Decompose
656
717
 
657
- The Grilled / Planning states spawn a planning-model subagent that breaks
658
- `TODO.md` into executable work packages under `.gtd/`:
718
+ The Grilled/Planning states spawn a planning-model subagent that breaks
719
+ `.gtd/TODO.md` into executable work packages under `.gtd/`:
659
720
 
660
721
  ```
661
722
  .gtd/
@@ -680,171 +741,64 @@ Rules:
680
741
  - **Task files are self-contained** — description, acceptance-criteria
681
742
  checkboxes, relevant file paths, constraints, and edge cases.
682
743
 
683
- Packages carry only their task `.md` files; the edge commits each built package
684
- `gtd: building`.
685
-
686
744
  ### Execute
687
745
 
688
- Execution is **one package per cycle**. gtd selects the single next package
689
- itself, names it in the prompt, and inlines its task files' full contents — the
690
- prompt is self-contained, so the agent never browses `.gtd/` or picks a package.
691
- A single cycle:
692
-
693
- 1. Spawn parallel execution-model workers for all tasks in the selected package
694
- (with the `tdd` skill).
695
- 2. If a worker fails (crash/timeout, not a test failure): ask the user to
696
- retry/skip/abort.
697
- 3. Leave all changes **uncommitted**. Do not commit, do not delete the package
698
- directory, do not run tests here.
699
- 4. Re-run gtd the next cycle's edge (Testing) commits the work `gtd: building`
700
- and runs `testCommand` to verify it.
701
-
702
- Verification is deterministic and lives in the edge, not the prompt: gtd runs
703
- the configured `testCommand` itself, captures stdout + stderr + the exit code,
704
- and the **machine** branches on it (green Agentic Review; red below cap →
705
- Fixing; red at/over cap Escalate).
706
-
707
- ## Q&A format inside TODO.md
708
-
709
- The agent never asks the user clarifying questions directly — it records
710
- uncertainty in `TODO.md` under `## Open Questions` instead. The grilling phase
711
- is gated by a single **convergence marker**: every open question carries a
712
- `<!-- user answers here -->` line directly beneath it. While _any_ marker is
713
- present, gtd **STOPs** and waits for you to answer inline.
714
-
715
- The `## Open Questions` section lives at the TOP of TODO.md (before the plan
716
- body). Each question looks like this:
717
-
718
- ```markdown
719
- ### What should pagination default to?
720
-
721
- **Recommendation:** 25 per page matches the admin tables elsewhere.
722
-
723
- <!-- user answers here -->
724
- ```
725
-
726
- To answer, replace the comment with your response:
727
-
728
- ```markdown
729
- ### What should pagination default to?
730
-
731
- **Recommendation:** 25 per page matches the admin tables elsewhere.
732
-
733
- 50 — these tables get long and 25 wastes a click for most users.
734
- ```
735
-
736
- On the next run the agent integrates the answer into the plan body and moves the
737
- question to the `## Resolved` graveyard at the bottom:
738
-
739
- ```markdown
740
- ## Resolved
741
-
742
- ### What should pagination default to?
743
-
744
- **Recommendation:** 25 per page — matches the admin tables elsewhere.
745
-
746
- **Answer:** 50 — these tables get long and 25 wastes a click for most users.
747
- ```
748
-
749
- When there are genuinely no open questions left, the agent writes the sentinel
750
- line `no open questions — run gtd to plan` and leaves **no** markers — a clean
751
- tree with no markers is what advances the plan to **Grilled** and decomposition.
752
-
753
- ## CLI flags
754
-
755
- ```
756
- Usage: gtd [command] [options]
757
-
758
- Commands:
759
- (default) Run the gtd driver loop — detect state, emit next prompt
760
- format <file> Format a markdown file in place
761
- review <target> Ad-hoc human review against a git ref or branch
762
-
763
- Options:
764
- --json Output structured JSON instead of plain text
765
- --verbose Show verbose output (thinking deltas, tool events)
766
- --debug Show debug-level internal information
767
- --version, -v Print version and exit
768
- --help, -h Print this help and exit
769
- ```
770
-
771
- `--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
772
- repository-state work — they run outside a repo and in any repo state.
773
-
774
- ## Subcommands
775
-
776
- gtd ships two subcommands: `format` and `review`.
777
-
778
- ## Review subcommand
779
-
780
- ```bash
781
- gtd review <target>
782
- ```
783
-
784
- Starts an explicit, on-demand human review of the diff between HEAD and
785
- `merge-base(<target>, HEAD)`. Use this when the automatic review base yields no
786
- diff (idle tree outside a process) or when you want to review against a specific
787
- base regardless of workflow state.
788
-
789
- ### Flow
790
-
791
- 1. `gtd review <target>` computes the diff HEAD adds over
792
- `merge-base(<target>, HEAD)`.
793
- 2. The edge writes an empty anchor commit `gtd: reviewing` (no content — just
794
- the marker).
795
- 3. The **Clean** state writes `REVIEW.md` with the computed diff and emits the
796
- normal review prompt. `--json` is accepted and enables auto-advance mode
797
- (same behavior as the default command).
798
- 4. The normal loop then drives: **Await Review** → **Done** → **Squashing**,
799
- collapsing back to the `gtd: reviewing` anchor commit.
800
-
801
- ### Error handling
802
-
803
- All errors exit with **code 1** and write a message to **stderr**:
804
-
805
- - **Missing target** — `gtd review` with no argument:
806
- `gtd review: missing target argument`
807
- - **Extra arguments** — `gtd review main extra`:
808
- `gtd review: too many arguments — expected one target, got: …`
809
- - **Unresolvable ref** — the target cannot be resolved by git:
810
- `gtd review: cannot resolve ref '<target>': <error message>`
811
- - **Empty diff** — the merge-base diff between `<target>` and HEAD is empty
812
- (nothing to review):
813
- `gtd review: nothing to review (<target> diff is empty after filtering)`
814
-
815
- ## Format subcommand
816
-
817
- `gtd format` formats a markdown file in place:
818
-
819
- ```bash
820
- gtd format <file>
821
- ```
822
-
823
- It uses a bundled prettier with a fixed, gtd-owned config (`parser: "markdown"`,
824
- `printWidth: 80`, `proseWrap: "always"`). The host repo's `.prettierrc` is
825
- **intentionally ignored** — determinism across consumer repos matters more than
826
- local style preferences.
827
-
828
- The grilling and clean prompts instruct the agent to run this command after
829
- every edit to `TODO.md` or `REVIEW.md`, so those files stay consistently
830
- formatted regardless of the host project's toolchain.
831
-
832
- ### Error handling
833
-
834
- All errors exit with **code 1** and write a message to **stderr**:
835
-
836
- - **Missing path** — `gtd format` with no argument:
837
- `gtd format: missing file path argument`
838
- - **Extra arguments** — `gtd format a.md b.md`:
839
- `gtd format: too many arguments — expected one path, got: …`
840
- - **Non-markdown file** — any extension other than `.md` or `.markdown`
841
- (case-insensitive):
842
- `gtd format: <file> is not a markdown file (expected .md or .markdown)`
843
- - **File not found** — the path does not exist:
844
- `gtd: skipped formatting <file>: not found`
845
-
846
- > [!NOTE] Upgrading gtd may reflow existing `TODO.md` files if the bundled
847
- > prettier major version changes.
746
+ Execution is **one package per cycle**. `gtd next` selects the single next
747
+ package itself, names it in the prompt, and inlines its task files' full
748
+ contents the agent never browses `.gtd/` or picks a package itself. A single
749
+ cycle:
750
+
751
+ 1. Spawn parallel execution-model workers for all tasks in the selected package.
752
+ 2. Leave all changes **uncommitted**. Do not commit, do not delete the package
753
+ directory, do not run tests.
754
+ 3. Finish the turn with `gtd step-agent` — the next hop's edge action commits
755
+ the work (`gtd(agent): building`) and runs `testCommand` to verify it.
756
+
757
+ ## Upgrading from v1 (BREAKING CHANGE)
758
+
759
+ v2 ships as a **major** semantic-release bump (`2.0.0`) so the binary and the
760
+ loop-driving text (this README, `skills/loop/SKILL.md`) can never skew against
761
+ each other. There is **no backward compatibility with the v1 command surface**:
762
+ the single mutating `gtd` command, marker/sentinel files, the `autoAdvance` JSON
763
+ field, and the `gtd: transport` handoff commit are all gone. `gtd` bare now
764
+ errors rather than driving a loop; use `gtd step-agent` / `gtd next` /
765
+ `gtd step` instead.
766
+
767
+ **Commit-history compatibility is one-way.** Any repo with v1-taxonomy history
768
+ in it (`gtd: new task`, `gtd: grilling`, `gtd: transport`, a bare
769
+ `gtd: reviewing` with no hash, …) upgrades cleanly: those subjects fall outside
770
+ v2's closed turn/routing grammar and parse as inert **boundary commits** they
771
+ are never mistaken for v2 workflow state and never error.
772
+
773
+ **Finish or clean up any in-flight v1 cycle first.** If a repo has an
774
+ **in-progress** v1 cycle steering files present (root-level `TODO.md`,
775
+ `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, or `.gtd/`) whose HEAD carries v1-only
776
+ commit subjects — the v2 binary does not know how to resume it: v1 steering
777
+ files have no v2 turn commit backing them, so a cold v2 invocation on that tree
778
+ can land in an unrecognized state. Either finish the v1 cycle to a clean
779
+ boundary with your existing v1 binary before upgrading, or manually clean up
780
+ (remove the steering files / `.gtd/`, commit the result) so the upgrade starts
781
+ from a plain boundary HEAD.
782
+
783
+ **Steering files moved into `.gtd/`.** Earlier v2 builds kept `TODO.md`,
784
+ `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, `HEALTH.md`, and `SQUASH_MSG.md` at the
785
+ repository root; they now live under `.gtd/`. Upgrade at a clean boundary (idle,
786
+ post-squash): a repo at rest needs nothing. Mid-cycle repos should either finish
787
+ the cycle on the old build first or move the root-level steering files into
788
+ `.gtd/` by hand and commit. History classification is backward-compatible — the
789
+ counter folds recognize both the old root paths and the new `.gtd/` paths in
790
+ existing commits.
791
+
792
+ **Re-copy the loop skill.** If you vendor `skills/loop/` into a consuming repo
793
+ or agent harness, upgrading the `gtd` binary also means re-copying that skill
794
+ from this release the v1 skill text still describes the old single-command
795
+ loop and will drive the new binary incorrectly.
796
+
797
+ For maintainers: this repo releases via `semantic-release` reading Conventional
798
+ Commits, and needs **no config change** for a major bump — but the release
799
+ commit/PR **must carry a `BREAKING CHANGE:` footer** (or a `!` after the type)
800
+ for `@semantic-release/commit-analyzer` to compute `2.0.0` rather than a
801
+ minor/patch bump.
848
802
 
849
803
  ## Development
850
804
 
@@ -852,9 +806,10 @@ All errors exit with **code 1** and write a message to **stderr**:
852
806
  npm install
853
807
  npm run dev # run from source, no build (node dev/run.mjs)
854
808
  npm run build # tsup → dist/gtd.bundle.mjs
855
- npm test # vitest unit tests (the pure resolver) --project unit
809
+ npm test # format:check, typecheck, lint, unit + e2e tests, fallow
810
+ npm run test:unit # vitest unit tests (the pure resolver) — --project unit
856
811
  npm run test:e2e # gherkin e2e via vitest + quickpickle — --project e2e
857
- npm run test:mutation # StrykerJS mutation testing
812
+ npm run test:mutation # StrykerJS mutation testing (manual only, ~2 min)
858
813
  npm run typecheck
859
814
  npm run lint
860
815
  ```
@@ -862,29 +817,20 @@ npm run lint
862
817
  ### Pre-commit hook
863
818
 
864
819
  A pre-commit hook is installed automatically via the `prepare` script when you
865
- run `npm install` on a fresh clone — no manual setup needed.
866
-
867
- The hook runs [lint-staged](https://github.com/lint-staged/lint-staged) with
820
+ run `npm install` on a fresh clone — no manual setup needed. The hook runs
821
+ [lint-staged](https://github.com/lint-staged/lint-staged) with
868
822
  [Prettier](https://prettier.io/), formatting every staged file before each
869
- commit:
870
-
871
- ```
872
- prettier --ignore-unknown --write
873
- ```
874
-
875
- This mirrors the `format:check` step enforced in CI (`prettier --check .`),
876
- keeping committed code consistently formatted without requiring a separate
877
- manual format pass.
823
+ commit (`prettier --ignore-unknown --write`), mirroring the `format:check` step
824
+ enforced in CI (`prettier --check .`).
878
825
 
879
826
  ### Prompt templates
880
827
 
881
828
  Each prompt-bearing state has a self-contained Eta template in
882
- `src/prompts/*.md` that owns its full prompt — header, context, body, and tail.
883
- Shared fragments live as partials in `src/prompts/partials/`: `header`, the
884
- context renderers (`context`, `package`, `diff`, `feedback`), and three tail
885
- variants (`auto-advance`, `neutral`, `stop`). Templates compose them via Eta's
886
- `<%~ include("@name", { … }) %>` syntax; dynamic values such as the resolved
887
- model string are injected as Eta variables (`<%= model %>`).
829
+ `src/prompts/*.md` that owns its full prompt — header, context, and body. Shared
830
+ fragments live as partials in `src/prompts/partials/`: `header`, the context
831
+ renderers (`diff`, `feedback`, `package`), and the single `agent-turn` tail
832
+ partial (the pinned "Finish your turn by running `gtd step-agent`. Then run
833
+ `gtd next` …" loop-closing instructions).
888
834
 
889
835
  At module load, `src/Prompt.ts` registers every template on a single `new Eta()`
890
836
  instance via `loadTemplate`. `readFile` and `resolvePath` are nulled afterward
@@ -894,16 +840,17 @@ bundle carries no runtime `fs` dependency.
894
840
  `buildPrompt(result, resolveModel?, output?)` selects the state's template,
895
841
  builds a view-model (model string, tail partial name, context), renders it,
896
842
  collapses runs of three or more blank lines to two, and ensures exactly one
897
- trailing newline.
843
+ trailing newline. It throws for the five states that render no prompt at all
844
+ (`testing`, `planning`, `close-package`, `done`, `health-check`) — those are
845
+ performed entirely by the edge.
898
846
 
899
847
  `npm run dev` runs `src/main.ts` directly via Node's native TypeScript
900
848
  type-stripping (requires Node 22.6+). It registers `dev/hooks.mjs`, which fills
901
849
  the two gaps the tsup build otherwise covers: resolving `./Foo.js` specifiers to
902
850
  the on-disk `./Foo.ts`, and importing `*.md` prompt files as text. Pass CLI args
903
- after `--`, e.g. `npm run dev -- format <file>`. The helpers live in `dev/`
904
- rather than `scripts/` because tsup wipes `dist/` (`clean: true`) on build.
851
+ after `--`, e.g. `npm run dev -- format <file>`.
905
852
 
906
- The decision core (`src/Machine.ts`) is pure and IO-free, so the whole 17-state
853
+ The decision core (`src/Machine.ts`) is pure and IO-free, so the whole 16-state
907
854
  ladder and both counter folds are trivially unit-testable in isolation; all
908
855
  git/filesystem IO is confined to the edge (`src/Events.ts`).
909
856
 
@@ -912,8 +859,10 @@ binary via the `bin` field in `package.json`.
912
859
 
913
860
  ### Mutation testing
914
861
 
915
- Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min).
916
- The single `stryker.config.json` mutates six core files:
862
+ Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min)
863
+ never run it as part of routine development; it is a deliberate,
864
+ manually-triggered check. The single `stryker.config.json` mutates six core
865
+ files:
917
866
 
918
867
  ```
919
868
  src/Machine.ts src/Prompt.ts src/Config.ts
@@ -921,56 +870,9 @@ src/Format.ts src/State.ts src/Events.ts
921
870
  ```
922
871
 
923
872
  `src/Git.ts` is excluded: the Cucumber harness stubs git at the Effect boundary,
924
- so Git.ts mutants have zero in-memory coverage. Measuring its post-refactor
925
- Live-tier kill rate is a follow-up before re-including it.
926
-
927
- **`process.chdir()` gotcha (resolved).** `@stryker-mutator/vitest-runner`
928
- hardcodes `pool: 'threads'` internally, and `process.chdir()` is unsupported in
929
- worker threads. Before the cwd refactor (package 01), four test files
930
- (`Events.test.ts`, `Git.test.ts`, `Config.test.ts`, `TestRunner.test.ts`) had to
931
- be excluded from all Stryker runs. The refactor eliminated those calls, letting
932
- all four files rejoin the run.
933
-
934
- Two additional notes: `vitest.related` is disabled for feature-file runs because
935
- feature files don't import source files directly (Stryker's coverage-based
936
- filtering would assign zero tests to every mutant). Compile-error mutants are
937
- counted as kills by the TypeScript checker — they represent real signal, not a
938
- configuration problem.
939
-
940
- Run `npm run test:mutation` after making changes to the mutated files to check
941
- whether surviving mutants increased. The HTML report lands in
942
- `reports/mutation/mutation.html` (git-ignored).
943
-
944
- ### Mutation testing
945
-
946
- Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min).
947
- The single `stryker.config.json` mutates six core files:
948
-
949
- ```
950
- src/Machine.ts src/Prompt.ts src/Config.ts
951
- src/Format.ts src/State.ts src/Events.ts
952
- ```
873
+ so `Git.ts` mutants have zero in-memory coverage.
953
874
 
954
- `src/Git.ts` is excluded: the Cucumber harness stubs git at the Effect boundary,
955
- so Git.ts mutants have zero in-memory coverage. Measuring its post-refactor
956
- Live-tier kill rate is a follow-up before re-including it.
957
-
958
- **`process.chdir()` gotcha (resolved).** `@stryker-mutator/vitest-runner`
959
- hardcodes `pool: 'threads'` internally, and `process.chdir()` is unsupported in
960
- worker threads. Before the cwd refactor (package 01), four test files
961
- (`Events.test.ts`, `Git.test.ts`, `Config.test.ts`, `TestRunner.test.ts`) had to
962
- be excluded from all Stryker runs. The refactor eliminated those calls, letting
963
- all four files rejoin the run.
964
-
965
- Two additional notes: `vitest.related` is disabled for feature-file runs because
966
- feature files don't import source files directly (Stryker's coverage-based
967
- filtering would assign zero tests to every mutant). Compile-error mutants are
968
- counted as kills by the TypeScript checker — they represent real signal, not a
969
- configuration problem.
970
-
971
- Run `npm run test:mutation` after making changes to the mutated files to check
972
- whether surviving mutants increased. The HTML report lands in
973
- `reports/mutation/mutation.html` (git-ignored).
875
+ The HTML report lands in `reports/mutation/mutation.html` (git-ignored).
974
876
 
975
877
  ## Releasing
976
878