@pmelab/gtd 1.10.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,33 +4,72 @@
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.
70
+ `gtd-loop`, installed alongside `gtd` (see below), is the packaged, ready-to-run
71
+ implementation of that same script for anyone who doesn't want to drive the loop
72
+ by hand.
34
73
 
35
74
  ## Installation
36
75
 
@@ -44,493 +83,535 @@ Or run without installing:
44
83
  npx @pmelab/gtd
45
84
  ```
46
85
 
47
- No config file, no setup subcommand.
86
+ No config file, no setup subcommand — `gtd` auto-initializes a `.gtdrc.json`
87
+ schema stub on first run (see [Auto-init](#auto-init)).
48
88
 
49
- ## Usage
89
+ ## Command reference
50
90
 
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).
56
-
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.
61
-
62
- ## JSON output mode
91
+ ```
92
+ Usage: gtd [command] [options]
63
93
 
64
- Pass `--json` to the default `gtd` invocation to receive machine-readable output
65
- instead of a plain prompt:
94
+ Commands:
95
+ step Advance the workflow as the human actor (to fixpoint)
96
+ step-agent Advance the workflow as the agent actor (to fixpoint)
97
+ next Print the prompt for whichever actor is awaited (no mutation)
98
+ status Predict the next commit and state from the working tree (no mutation)
99
+ review <target> Anchor an ad-hoc human review against a git ref or branch
100
+ format <file> Format a markdown file in place
66
101
 
67
- ```bash
68
- gtd --json
102
+ Options:
103
+ --json Output structured JSON instead of plain text
104
+ --version, -v Print version and exit
105
+ --help, -h Print this help and exit
69
106
  ```
70
107
 
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.
108
+ `--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
109
+ repository-state work they run outside a repo and in any repo state. Bare
110
+ `gtd` (no subcommand) is a usage error: it prints the help text and exits 1
111
+ without touching the repository. Every other command must be run from the
112
+ **repository root** — gtd derives steering files, diffs, and pathspecs relative
113
+ to cwd, so it refuses with a clear error if invoked from a subdirectory.
74
114
 
75
- ### Output shape
115
+ `--json` is the only long option. Any other `--` option (including a typo like
116
+ `--jsn`) is rejected with a usage error rather than silently ignored, so a
117
+ mistyped flag can never degrade a JSON caller to plain-text mode.
76
118
 
77
- In `--json` mode gtd emits a **single-line JSON object** to stdout:
119
+ ### `gtd step` / `gtd step-agent`
78
120
 
79
- ```json
80
- { "state": "building", "autoAdvance": true, "prompt": "..." }
81
- ```
121
+ Both drive the **same fixpoint loop** — gather → resolve → perform the returned
122
+ edge action repeat differing only in which actor's turn they are allowed to
123
+ capture:
82
124
 
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.
125
+ - **`gtd step`** captures the **human** turn at whichever gate is awaiting one.
126
+ - **`gtd step-agent`** captures the **agent** turn.
93
127
 
94
- ### Loop-ownership division of labor
128
+ **Fixpoint advance.** A single invocation may author several commits: it authors
129
+ the awaited actor's turn commit, then keeps performing any further mid-chain
130
+ routing (a test run, a routing commit, a package close, …) until it reaches a
131
+ rest where a prompt would be shown, or a fixpoint where nothing changed.
132
+ `gtd step`/`gtd step-agent` never print a prompt themselves — that's
133
+ `gtd next`'s job.
95
134
 
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.
135
+ **Idempotence.** Re-running the same command again once the tree is settled at a
136
+ rest authors **zero** new commits. It exits 0 while the rest still awaits that
137
+ command's actor (an inert empty agent turn, the idle health check); once the
138
+ rest awaits the _other_ actor, the re-run is an out-of-turn refusal — still zero
139
+ commits, but non-zero exit.
98
140
 
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.
141
+ **Out-of-turn refusal.** Human and agent turns are strictly separated: the wrong
142
+ mutator always errors, at every state, on clean and dirty trees alike.
143
+ `gtd step-agent` while a human turn is awaited refuses with
144
+ `"<state> awaits a human turn — run \`gtd step\`"`; `gtd
145
+ step`while an agent turn is awaited refuses with`"<state> awaits an agent turn —
146
+ run \`gtd
147
+ 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:
148
+ planning` commit lands) stay pending in the working tree and ride along as input
149
+ to the agent's next captured turn; left unamended, the build proceeds.
102
150
 
103
- Example driver script:
151
+ **Red-test fixpoints exit 0.** A red test run below the fix-attempt cap (or the
152
+ health-fix cap) still writes its findings and commits — it is a normal,
153
+ successful step of the loop, not a failure of the `step`/`step-agent`
154
+ invocation. `step`/`step-agent` only exit non-zero for a genuine refusal or an
155
+ operational error (bad config, missing test binary, corrupted state).
104
156
 
105
- ```bash
106
- #!/usr/bin/env bash
107
- set -euo pipefail
157
+ **Output.** Plain mode prints one `committed: <subject>` line per commit this
158
+ invocation authored (oldest→newest), then a final `state: <state>` line:
108
159
 
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
160
+ ```
161
+ committed: gtd(human): grilling
162
+ committed: gtd: grilled
163
+ state: grilled
115
164
  ```
116
165
 
117
- ### Error behavior
166
+ `--json` emits `{state, actions, commits}` instead (see
167
+ [JSON schemas](#json-schemas)).
118
168
 
119
- Errors are reported **inside** the JSON object rather than as unstructured text:
169
+ ### `gtd next`
170
+
171
+ Pure prompt emitter — it **never mutates** the repository. It reports whichever
172
+ actor is currently awaited and, if the tree is at a genuine rest, the full
173
+ prompt for that actor.
174
+
175
+ **Purity.** No commits, no file writes, no test runs — `gtd next` only gathers
176
+ and resolves.
177
+
178
+ **Dirty-tree refusal.** If the working tree has pending changes outside the
179
+ steering-file set, `gtd next` refuses rather than guess at a prompt for a state
180
+ that hasn't been captured yet:
120
181
 
121
- ```json
122
- { "state": "error", "autoAdvance": false, "prompt": "<message>" }
123
182
  ```
183
+ 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)
184
+ ```
185
+
186
+ **Pending.** If HEAD is mid-chain — bookkeeping the next `step`/`step-agent`
187
+ invocation would perform before reaching a rest — `gtd next` reports
188
+ `pending: true` with no prompt. Mid-chain bookkeeping is invoker-agnostic, so
189
+ either mutator resumes it; the report names the actor whose chain it is. In
190
+ plain mode an agent-driven checkpoint prints `"mid-chain checkpoint — run \`gtd
191
+ step-agent\` to continue, then run \`gtd next\`
192
+ again"`, a human-driven one prints `"mid-chain checkpoint — run \`gtd step\` to
193
+ continue"`.
194
+
195
+ **Agent tail lines.** In plain-mode output, a prompt for the **agent** actor
196
+ ends with the pinned tail:
124
197
 
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
280
198
  ```
199
+ Finish your turn by running `gtd step-agent`. Then run `gtd next` and follow
200
+ its output — repeat this cycle as long as the output is addressed to you (the
201
+ agent); when it awaits the human, stop and hand off.
202
+ ```
203
+
204
+ The first sentence closes the current turn; the second closes the outer loop —
205
+ it is what lets a plain-text agent chain multiple iterations (e.g. successive
206
+ test/fix cycles) without an external driver, until a human gate is reached.
207
+ Human-actor prompts carry no tail. `--json` output never embeds the tail into
208
+ `prompt` either — the structured `actor` field (see JSON schemas below) carries
209
+ the same information: `"agent"` means another agent round, `"human"` means stop
210
+ and hand off.
211
+
212
+ ### `gtd status`
281
213
 
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).
214
+ Pure, read-only **dry-run prediction** the same gather+resolve `gtd next`
215
+ runs, but reporting a prediction of the next turn rather than the actual prompt.
216
+ Performs no git mutation, no test run, no file write — guaranteed side-effect
217
+ free, including on a dirty tree.
285
218
 
286
- ### Illegal combinations
219
+ Prints four fields:
287
220
 
288
- These never arise in normal flow; if seen, `gtd` hard-errors rather than
289
- guessing:
221
+ ```
222
+ State: grilling
223
+ Awaits: human
224
+ Predicted commit: gtd(human): grilling
225
+ Predicted state: grilling
226
+ ```
290
227
 
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)
228
+ - **State** the currently resolved state.
229
+ - **Awaits** the actor (`human` or `agent`) whose turn it is.
230
+ - **Predicted commit** — the subject `step`/`step-agent` would author next, or
231
+ `(none)` at a fixpoint (e.g. idle with nothing to do).
232
+ - **Predicted state** — the state that commit would land in.
301
233
 
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).
234
+ `gtd status` takes no arguments extra positional args are rejected.
305
235
 
306
- ### Single writer, linear branch
236
+ ### `gtd review <target>`
307
237
 
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).
238
+ A pure mutator that **anchors, then exits** it never prints a prompt itself.
239
+ Use it to start an ad-hoc human review against an explicit git ref or branch,
240
+ independent of the automatic review base the workflow otherwise computes.
311
241
 
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`:
242
+ 1. Refuses on a dirty tree.
243
+ 2. Resolves `<target>` via merge-base semantics and computes the diff HEAD adds
244
+ over `merge-base(<target>, HEAD)`.
245
+ 3. Refuses if that diff is empty after filtering ("nothing to review").
246
+ 4. Authors exactly one commit: `gtd: reviewing <full-hash-of-the-base>`.
247
+ 5. Prints a short confirmation pointing at `gtd next` — it does **not** print
248
+ the review prompt itself.
315
249
 
316
250
  ```bash
317
- git add -A && git commit -m "gtd: transport" # on the source machine
318
- git push # then pull on the far side
251
+ gtd review main
252
+ # anchored review at <hash> — run `gtd next` to get the review prompt
253
+ gtd next --json
254
+ # {"actor":"agent", ...} — the review-record prompt scoped to that anchor
319
255
  ```
320
256
 
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.
257
+ Errors (all exit 1, message on stderr):
404
258
 
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
- ```
259
+ - Missing target: `gtd review: missing target argument`
260
+ - Extra arguments:
261
+ `gtd review: too many arguments — expected one target, got: …`
262
+ - Unresolvable ref: `gtd review: cannot resolve ref '<target>': <error message>`
263
+ - Empty diff:
264
+ `gtd review: nothing to review (<target> diff is empty after filtering)`
265
+
266
+ ### `gtd format <file>`
267
+
268
+ Unchanged from v1: formats a markdown file in place with a bundled prettier
269
+ (`parser: "markdown"`, `printWidth: 80`, `proseWrap: "always"`), ignoring the
270
+ host repo's own `.prettierrc` so `.gtd/TODO.md`/`.gtd/REVIEW.md` stay
271
+ consistently formatted regardless of the host project's toolchain. Rejects
272
+ `--json` (exit 1, `gtd format does not accept --json`) — it is a plain file
273
+ operation, not a v2 state command.
274
+
275
+ Errors (all exit 1, message on stderr):
411
276
 
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.
277
+ - Missing path: `gtd format: missing file path argument`
278
+ - Extra arguments: `gtd format: too many arguments expected one path, got: …`
279
+ - Non-markdown file:
280
+ `gtd format: <file> is not a markdown file (expected .md or .markdown)`
281
+ - File not found: `gtd: skipped formatting <file>: not found`
282
+
283
+ ## JSON schemas
284
+
285
+ Pass `--json` to `step`, `step-agent`, `next`, or `status` for machine-readable
286
+ single-line JSON output instead of plain text.
287
+
288
+ **`step` / `step-agent`** — `{state, actions, commits}`:
289
+
290
+ ```json
291
+ {
292
+ "state": "grilled",
293
+ "actions": ["capture the human turn as \"gtd(human): grilling\""],
294
+ "commits": ["gtd(human): grilling", "gtd: grilled"]
295
+ }
296
+ ```
418
297
 
419
- ### Health-fix loop (`fixAttemptCap`, `squash`no new config)
298
+ - `state` — the final resolved state after the fixpoint loop settled.
299
+ - `actions` — human-readable descriptions of every edge action this invocation
300
+ performed, oldest→newest.
301
+ - `commits` — every commit subject this invocation authored, oldest→newest.
420
302
 
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.
303
+ **`next`** `{state, actor, pending, prompt}`:
424
304
 
305
+ ```json
306
+ {
307
+ "state": "building",
308
+ "actor": "agent",
309
+ "pending": false,
310
+ "prompt": "..."
311
+ }
425
312
  ```
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
313
+
314
+ - `state` — the resolved state.
315
+ - `actor` — `"human"` or `"agent"`: who owns the next move. This is the single
316
+ loop-driver signal: `"agent"` means proceed with another round — act on
317
+ `prompt` when present, then run `gtd step-agent`; at an agent-driven pending
318
+ checkpoint (`prompt` is `null`, nothing to act on) just run `gtd step-agent`.
319
+ `"human"` means halt and hand off (a human rest, whose prompt body already
320
+ tells the human what to do, or a human-driven pending checkpoint resumed by
321
+ `gtd step`).
322
+ - `pending` `true` at a mid-chain HEAD (no prompt yet — resume with a mutator
323
+ first); `false` at a genuine rest.
324
+ - `prompt` — the full prompt markdown when `pending` is `false`, else `null`.
325
+
326
+ **`status`** — `{state, actor, predictedCommit, predictedState}`:
327
+
328
+ ```json
329
+ {
330
+ "state": "grilling",
331
+ "actor": "human",
332
+ "predictedCommit": "gtd(human): grilling",
333
+ "predictedState": "grilling"
334
+ }
436
335
  ```
437
336
 
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**:
337
+ `predictedCommit` is `null` when the next invocation would author nothing (e.g.
338
+ idle with a green health check).
456
339
 
340
+ **Error envelope** — every command, in `--json` mode, reports failures inside
341
+ the JSON object rather than as unstructured text, and still exits 1:
342
+
343
+ ```json
344
+ { "state": "error", "prompt": "<message>" }
457
345
  ```
458
- Testing(green) → Agentic Review → empty FEEDBACK → Close package → next package
459
-
460
- └─ findings Fixing(gtd: feedback) Testing Agentic Review
346
+
347
+ There is no auto-advance flag anywhere in the wire format — `actor` replaces it.
348
+ The caller decides whether to keep looping based on `actor` (halt on `"human"`)
349
+ and `pending` (re-run `step`/`step-agent` first when `true`), not on a boolean
350
+ auto-advance flag.
351
+
352
+ ## The reference loop driver
353
+
354
+ A minimal bash implementation of the pinned two-beat protocol, driving an agent
355
+ CLI (e.g. `claude -p`) against `gtd --json` output. This is the authoritative
356
+ reference for what a loop driver must do; keep any other implementation
357
+ (including `skills/loop/SKILL.md`) consistent with it rather than editing both
358
+ independently.
359
+
360
+ ```bash
361
+ #!/usr/bin/env bash
362
+ set -euo pipefail
363
+
364
+ while true; do
365
+ # 1. Advance the machine's own agent-owned bookkeeping to a fixpoint.
366
+ gtd step-agent --json >/dev/null || true
367
+
368
+ # 2. Ask who's up next. `actor` is the single "proceed" signal.
369
+ next="$(gtd next --json)"
370
+ actor="$(jq -r .actor <<<"$next")"
371
+ prompt="$(jq -r .prompt <<<"$next")"
372
+
373
+ if [[ "$actor" != "agent" ]]; then
374
+ echo "Halting — the human owns the next move."
375
+ break
376
+ fi
377
+
378
+ if [[ "$prompt" == "null" ]]; then
379
+ # Agent-driven pending checkpoint: nothing to act on — loop back to
380
+ # step 1, whose `gtd step-agent` resumes the mid-chain bookkeeping.
381
+ continue
382
+ fi
383
+
384
+ # Agent's turn: feed the prompt to the agent, then let it finish with
385
+ # `gtd step-agent` itself (the prompt's tail instructs it to).
386
+ claude -p "$prompt" --dangerously-skip-permissions
387
+ done
461
388
  ```
462
389
 
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.
390
+ The agent is expected to run `gtd step-agent` itself once it finishes acting on
391
+ the prompt (the plain-mode tail says exactly this) the driver's own
392
+ `step-agent` calls exist to advance any bookkeeping the agent doesn't own
393
+ (routing commits, test runs) between agent turns.
394
+
395
+ The loop halts on `actor: "human"` alone: a human rest (`pending: false`, the
396
+ prompt body addresses the human) or a human-driven pending checkpoint
397
+ (`pending: true`, resumed by the human's own `gtd step`). Everything the agent
398
+ side can drive — agent rests and agent-driven checkpoints — reports
399
+ `actor: "agent"`, so multiple agent turns and commits (e.g. successive test/fix
400
+ cycles, a force-approved package close) chain without human involvement until an
401
+ actual human gate is hit.
402
+
403
+ `bin/gtd-loop`, installed as the `gtd-loop` binary, is the packaged
404
+ implementation of this exact script kept in sync with it the same way
405
+ `skills/loop/SKILL.md` is. It additionally attempts `gtd step` (not just
406
+ `gtd step-agent`) every iteration, so a plain rerun after you've edited a file
407
+ at a human gate (no commit needed) picks up your edit and keeps going, and it
408
+ halts with a diagnostic if the same state and prompt repeat with no progress
409
+ (see `skills/loop/SKILL.md`'s "Stall detection").
410
+
411
+ ### Using a different agent
412
+
413
+ `gtd-loop` defaults to
414
+ `claude -p "$GTD_LOOP_PROMPT" --dangerously-skip-permissions`, but the agent
415
+ invocation is swappable: set `GTD_LOOP_AGENT_CMD` to any shell command, and it
416
+ runs with the prompt available as `$GTD_LOOP_PROMPT` in its environment. For
417
+ example, to drive a different agent CLI:
418
+
419
+ ```bash
420
+ GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop
421
+ ```
422
+
423
+ ## States & subjects overview
424
+
425
+ `resolve()` lands on exactly one of **16 states**: `grilling`, `grilled`,
426
+ `planning`, `building`, `testing`, `fixing`, `escalate`, `agentic-review`,
427
+ `close-package`, `review`, `await-review`, `done`, `squashing`, `idle`,
428
+ `health-check`, `health-fixing`. Each state has a fixed awaited actor (see
429
+ `awaitedActor` in `src/Machine.ts`): `idle`, `escalate`, and `await-review`
430
+ await the **human**; every other state awaits the **agent**.
431
+
432
+ For the full precedence ladder, illegal combinations, and the counter folds that
433
+ drive the fix loops, see [STATES.md](STATES.md) this section is a summary.
434
+
435
+ ### Turn commits `gtd(<actor>): <gate>`
436
+
437
+ Authored by `gtd step`/`gtd step-agent` as the first commit of a fresh chain.
438
+ The closed set of gates:
439
+
440
+ | Gate | Authored by |
441
+ | ---------------- | ------------------------------------------------------------------ |
442
+ | `grilling` | human (answers) / agent (plan iteration) |
443
+ | `grilled` | agent (converged, ready to decompose) |
444
+ | `building` | agent (package work, or human feedback while agent is out of turn) |
445
+ | `fixing` | agent (test-fix or review-fix round) |
446
+ | `agentic-review` | agent (writes .gtd/FEEDBACK.md verdict) |
447
+ | `review` | agent (writes .gtd/REVIEW.md) / human (approves or gives feedback) |
448
+ | `squashing` | agent (overwrites .gtd/SQUASH_MSG.md) |
449
+ | `health-fixing` | agent (idle health-check repair) |
450
+ | `escalate` | human (deletes .gtd/ERRORS.md to resume) |
451
+
452
+ ### Routing commits `gtd: <phase>`
453
+
454
+ Bookkeeping the machine authors itself between turns, never a turn a human or
455
+ agent "wins": `gtd: grilled`, `gtd: planning`, `gtd: tests green`,
456
+ `gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
457
+ `gtd: review feedback`, `gtd: done`, `gtd: squash template`,
458
+ `gtd: reviewing <hash>` (parameterized, from `gtd review`), `gtd: health-check`,
459
+ `gtd: health-fix`.
460
+
461
+ Everything else — any non-`gtd` subject, and any `gtd: *` subject outside this
462
+ closed set — is a **boundary commit**: inert as far as the machine's grammar is
463
+ concerned. See [Upgrading from v1](#upgrading-from-v1-breaking-change) for why
464
+ this matters on upgrade.
465
+
466
+ ## Workflow walkthroughs
467
+
468
+ ### Grilling
469
+
470
+ A dirty tree at a boundary HEAD (a fresh idea, sketched in a file or just left
471
+ as pending code) is captured in **one** human turn: `gtd step` commits
472
+ everything pending as `gtd(human): grilling` — nothing is reverted or seeded,
473
+ the captured files stay in history. `gtd next` hands the agent that turn's diff;
474
+ the agent develops `.gtd/TODO.md` into a concrete plan **in one turn**,
475
+ proposing a **suggested default** for every open question, and leaves
476
+ `.gtd/TODO.md` uncommitted for `gtd(agent): grilling`.
477
+
478
+ There are no markers to answer — the human either:
479
+
480
+ - **Accepts the suggested defaults**: runs a clean `gtd step` at the answer
481
+ gate. An empty `gtd(human): grilling` turn plus routing `gtd: grilled` lands
482
+ automatically, and `gtd next` emits the decompose prompt.
483
+ - **Edits `.gtd/TODO.md`** with real answers, then runs `gtd step`, which
484
+ captures the edit as a fresh `gtd(human): grilling` turn and hands it back to
485
+ the agent for another round.
486
+
487
+ ### Build lifecycle: budgets
488
+
489
+ Once decomposed, `.gtd/` holds ordered work packages. `gtd next` at
490
+ `gtd: planning`/`gtd: package done` selects the lowest-numbered remaining
491
+ package and inlines only its task files. The agent builds it and leaves the work
492
+ **uncommitted**; the next invocation's edge action commits it (the
493
+ `gtd(agent): building` turn commit) and runs `testCommand`.
494
+
495
+ - **Green** → Agentic Review.
496
+ - **Red, below `fixAttemptCap`** (default 3) → write findings, commit
497
+ `gtd: errors`, rest at **Fixing** for the agent.
498
+ - **Red, at/over the cap** → write `.gtd/ERRORS.md` instead, commit
499
+ `gtd: errors`, rest at **Escalate** — a human gate. Deleting `.gtd/ERRORS.md`
500
+ and landing that deletion as `gtd(human): escalate` resets the budget and
501
+ re-tests from zero in the same invocation.
502
+
503
+ ### Agentic review
504
+
505
+ A green test run always rests at **Agentic Review**: the agent reviews the
506
+ package's accumulated diff against its task specs and writes `.gtd/FEEDBACK.md`.
507
+ An **empty** `.gtd/FEEDBACK.md` is the approval signal — the same
508
+ `gtd(agent): agentic-review` turn closes the package (`gtd: package done`,
509
+ removing `.gtd/FEEDBACK.md` and the finished package directory) in one
510
+ invocation. Non-empty findings rest for the fixing prompt; fixing loops back
511
+ through the test gate and re-reviews. Once `reviewFixCount >= reviewThreshold`
512
+ (default 3) within a package, Agentic Review **force-approves** without ever
513
+ writing `.gtd/FEEDBACK.md` — so a package can never review-loop forever. The
514
+ findings round that crosses the threshold still gets its fixing round; the
515
+ force-approve close then fires at the next green re-test instead of another
516
+ review. (Any agentic-review turn that touches `.gtd/FEEDBACK.md` counts toward
517
+ the threshold — including the approval write itself; an approval that crosses
518
+ the threshold simply closes the package as usual.) Setting
519
+ `agenticReview: false` force-approves every package immediately.
520
+
521
+ A **do-nothing agent invocation** — `gtd step-agent` on a clean tree at ANY
522
+ agent-awaited rest whose move is a file artifact (`grilling`, `grilled`,
523
+ `building`, `fixing`, `agentic-review`, `review`, and `squashing` while
524
+ `.gtd/SQUASH_MSG.md` still holds the unmodified template) — is inert: zero
525
+ commits, no state consumed; `gtd next` re-emits the same prompt. This is
526
+ load-bearing for the loop protocol, whose every iteration opens with
527
+ `gtd step-agent` before the agent has acted: without the guard that opening beat
528
+ would author junk empty turns — and worse, consume workflow state (an empty
529
+ decompose turn would delete `.gtd/TODO.md` with no packages written; an empty
530
+ squashing turn would squash the cycle under the placeholder template). The same
531
+ guards hold at the classification layer for histories that already carry such
532
+ turns: a `gtd(agent): grilled` HEAD only routes to `gtd: planning` when packages
533
+ exist, a `gtd(agent): review` HEAD only routes to `gtd: awaiting review` when
534
+ `.gtd/REVIEW.md` exists, and a squashing turn only squashes once the template
535
+ has been overwritten. The one deliberate exception is `health-fixing`, whose
536
+ empty turn is meaningful (the failure may have been environmental — the machine
537
+ removes `.gtd/HEALTH.md` and re-tests). Human gates are unaffected: an empty
538
+ **human** turn stays a signal (accept-defaults at grilling, clean approval at
539
+ review).
540
+
541
+ ### Human review gate
542
+
543
+ Once `.gtd/` is fully closed, the machine writes `.gtd/REVIEW.md` and rests at
544
+ **await-review**, awaiting the human. Approval is any of:
545
+
546
+ - A **clean** `gtd step` (nothing edited) — an empty `gtd(human): review` turn
547
+ plus routing `gtd: done`.
548
+ - Flipping only `- [ ]` → `- [x]` checkboxes in `.gtd/REVIEW.md` — checkbox-only
549
+ edits are also treated as clean approval.
550
+
551
+ Any **substantive** edit — to `.gtd/REVIEW.md` prose, or to the reviewed code
552
+ itself — is feedback: `gtd(human): review` plus routing `gtd: review feedback`,
553
+ `.gtd/REVIEW.md` removed, and `gtd next` re-emits a grilling prompt to the agent
554
+ that inlines the human's finding.
555
+
556
+ ### Squash
557
+
558
+ With `squash: true` (the default), `gtd: done` is **not** a rest — the same
559
+ chain continues straight to `gtd: squash template`, writing and committing a
560
+ `.gtd/SQUASH_MSG.md` template. `gtd next` then emits the squashing prompt: the
561
+ agent overwrites `.gtd/SQUASH_MSG.md` with a real conventional-commits message
562
+ (drawing on grilling-round decisions from history) and finishes its turn.
563
+ `gtd step-agent` then performs the squash itself: `git reset --soft <base>` +
564
+ `git commit`, collapsing every intermediate `gtd: *` commit of the cycle into
565
+ one — including any review-feedback detours: the squash base is the cycle's
566
+ ORIGINAL start (the first grilling run since the previous `gtd: done` boundary,
567
+ or the `gtd: reviewing <hash>` anchor for an ad-hoc review cycle), not the most
568
+ recent re-grilling round — the collapse folds the whole cycle into one, using
569
+ the overwritten message's content verbatim (turn position, not message content,
570
+ triggers the squash). With `squash: false`, `gtd: done` is the resting boundary
571
+ and no template is ever written.
572
+
573
+ ### Health check
574
+
575
+ Outside any process (idle, nothing to review, no steering files), `gtd step`
576
+ runs `testCommand` as a health check rather than settling immediately. Green
577
+ settles idle with zero commits. Red below `fixAttemptCap` writes
578
+ `.gtd/HEALTH.md` and rests at **Health Fixing** for the agent; the fixer's own
579
+ turn (`gtd(agent): health-fixing`) removes `.gtd/HEALTH.md` and re-tests in the
580
+ same chain — a green re-test continues to squash (if enabled) or idle; red
581
+ repeats the health-fix loop; red at the cap writes `.gtd/ERRORS.md` and
582
+ escalates.
583
+
584
+ ### Escalate / budget reset
585
+
586
+ `.gtd/ERRORS.md` present is always a human gate, regardless of which loop wrote
587
+ it (test-fix or health-fix). Deleting `.gtd/ERRORS.md` and running `gtd step`
588
+ records the deletion as the human's `gtd(human): escalate` turn, which
589
+ **immediately re-tests in the same invocation** — this resets the relevant
590
+ fix-attempt budget to zero.
591
+
592
+ ## States & subjects: overview table
593
+
594
+ | State | Awaits | Turn/routing subject at rest |
595
+ | ---------------- | -------------- | ---------------------------------------------------------------- |
596
+ | `grilling` | human or agent | `gtd(human): grilling` / `gtd(agent): grilling` |
597
+ | `grilled` | agent | `gtd: grilled` |
598
+ | `planning` | agent | `.gtd/` modified |
599
+ | `building` | agent | `gtd: planning` / `gtd: package done` |
600
+ | `testing` | — (edge-only) | mid-chain only |
601
+ | `fixing` | agent | `gtd: errors` |
602
+ | `escalate` | human | `.gtd/ERRORS.md` present |
603
+ | `agentic-review` | agent | `gtd: tests green` |
604
+ | `close-package` | — (edge-only) | mid-chain only |
605
+ | `review` | agent | `gtd: package done` (no more packages) / `gtd: reviewing <hash>` |
606
+ | `await-review` | human | `gtd: awaiting review` |
607
+ | `done` | — (edge-only) | `gtd: done` |
608
+ | `squashing` | agent | `gtd: squash template` |
609
+ | `idle` | human | no steering files, green health check |
610
+ | `health-check` | — (edge-only) | mid-chain only |
611
+ | `health-fixing` | agent | `.gtd/HEALTH.md` present |
612
+
613
+ See [STATES.md](STATES.md) for the full precedence ladder, the counter folds,
614
+ and every illegal steering-file combination.
534
615
 
535
616
  ## Configuration
536
617
 
@@ -548,37 +629,34 @@ built-in defaults apply. Supported filenames (searched in this order):
548
629
  ### Schema
549
630
 
550
631
  - **`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.
632
+ after a build turn, and on the idle health-check path.
553
633
  - **`fixAttemptCap`** (non-negative integer, default `3`) — the test-fix budget:
554
634
  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).
635
+ escalated to `.gtd/ERRORS.md` (Escalate). `0` disables the cap (escalates
636
+ immediately on the first red run). Also reused as the health-fix budget no
637
+ separate config key.
558
638
  - **`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.
639
+ many agentic-review findings rounds are allowed per package before Agentic
640
+ Review force-approves.
561
641
  - **`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.
642
+ per-package Agentic Review gate. Set `false` to force-approve every package
643
+ and proceed directly to human review.
644
+ - **`squash`** (boolean, default `true`) — after `gtd: done`, collapse the
645
+ cycle's `gtd: *` commits into a single conventional-commits commit. Set
646
+ `false` to keep the granular history.
569
647
  - **`models`** — model selection for the subagent-spawning states:
570
648
  - `planning` — high-reasoning tier (default `claude-opus-4-8`), used by
571
- `decompose`, `grilling`, `agentic-review`, and `clean`.
649
+ `decompose` (the `grilled`/`planning` states), `grilling`, `agentic-review`,
650
+ and `clean` (the `review`/`squashing` states).
572
651
  - `execution` — everyday tier (default `claude-sonnet-4-8`), used by
573
652
  `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).
653
+ - `states.*` — per-state overrides keyed by `decompose`, `grilling`,
654
+ `building`, `fixing`, `agentic-review`, `clean`. Unknown `states` keys are
655
+ **rejected**.
656
+ - **`$schema`** (string, optional) — stripped before validation, so it never
657
+ counts as an unknown key. Point it at the published schema for editor-backed
658
+ autocompletion. A `schema.json` is generated from the config schema at build
659
+ time and ships with the package.
582
660
 
583
661
  ### Validation and errors
584
662
 
@@ -586,50 +664,38 @@ If a config file fails to load or is invalid, gtd **exits with code 1** and
586
664
  writes a human-readable error to **stderr** (never stdout):
587
665
 
588
666
  - **Parse errors** (malformed YAML/JSON) — message includes the offending
589
- filename, e.g. `gtd: /path/to/.gtdrc: unexpected token`.
667
+ filename.
590
668
  - **Non-object top-level** — a YAML list or `null` at the root is rejected with
591
669
  the filename in the message.
592
670
  - **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.
671
+ `Invalid gtd config: <field>: <reason>`.
595
672
  - **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).
673
+ found (`ENOENT`), gtd exits 1 with `gtd: test command not found: <command>` on
674
+ stderr. A non-zero test _exit code_ is not an error it drives the normal red
675
+ path.
600
676
 
601
677
  ### Lookup and precedence
602
678
 
603
679
  gtd walks from the current working directory **up to your home directory** (or
604
680
  to the filesystem root when cwd is outside home), collecting every `.gtdrc` it
605
681
  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`.
682
+ (cwd) config winning** on conflicts — so a shared `.gtdrc` in a worktree-parent
683
+ directory cascades to every checkout beneath it, while any individual checkout
684
+ can still override settings with its own `.gtdrc`.
611
685
 
612
686
  ### Auto-init
613
687
 
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.
688
+ On every **state command** (`step`, `step-agent`, `next`, `status`, `review`)
689
+ that has passed the repo-root guard, if the cwd→root walk finds **no** config
690
+ anywhere, gtd creates and commits a starter `.gtdrc.json` at the repository root
691
+ containing only a `$schema` link. Auto-init never runs for `--version`/`--help`,
692
+ `format`, bare/unknown commands, or an invocation refused by the repo-root guard
693
+ — those perform no repository mutation of any kind. On a repo with no commits
694
+ yet, or whose HEAD is a plain (non-`gtd:`) commit, the stub is committed as its
695
+ own `chore: add .gtdrc.json`. If HEAD is already a `gtd:`-owned commit
696
+ (mid-workflow), the stub is instead **amended into HEAD** — stacking a fresh
697
+ boundary commit there would produce an unrecognized HEAD most workflow states
698
+ can't resolve past.
633
699
 
634
700
  ### Example
635
701
 
@@ -648,14 +714,32 @@ models:
648
714
  building: claude-sonnet-4-8
649
715
  ```
650
716
 
651
- ## Build orchestration
717
+ ## Repository requirements
718
+
719
+ - **Single writer, linear branch.** State is folded from **first-parent**
720
+ history only. A merge commit at HEAD is unsupported (documented, not handled)
721
+ — it degrades gracefully on the default branch rather than crashing, but do
722
+ not rely on merge commits mid-cycle.
723
+ - **Test/build artifacts must be gitignored.** This is **load-bearing**, not a
724
+ style preference: every fixpoint hop in `gtd step`/`gtd step-agent` detects
725
+ "clean" via `git status --porcelain`, which silently omits anything matched by
726
+ `.gitignore`. If your `testCommand` (or the build it triggers) writes
727
+ tracked-but-untracked output — a `dist/`, a coverage report, a log file — into
728
+ the working tree, the tree never goes clean after a green test run, and the
729
+ fixpoint loop cannot converge: it will either loop forever re-detecting a
730
+ "dirty" boundary or misclassify build output as the human's next feature
731
+ capture. Gitignore every path your test/build toolchain writes before wiring
732
+ gtd into a repo.
733
+ - **Repository root invocation.** Every subcommand except `--help`/`--version`
734
+ must run from the git repository root — steering files and diffs are resolved
735
+ against the process cwd.
652
736
 
653
- When a plan is finalized, gtd enters build mode.
737
+ ## Build orchestration
654
738
 
655
739
  ### Decompose
656
740
 
657
- The Grilled / Planning states spawn a planning-model subagent that breaks
658
- `TODO.md` into executable work packages under `.gtd/`:
741
+ The Grilled/Planning states spawn a planning-model subagent that breaks
742
+ `.gtd/TODO.md` into executable work packages under `.gtd/`:
659
743
 
660
744
  ```
661
745
  .gtd/
@@ -680,248 +764,64 @@ Rules:
680
764
  - **Task files are self-contained** — description, acceptance-criteria
681
765
  checkboxes, relevant file paths, constraints, and edge cases.
682
766
 
683
- Packages carry only their task `.md` files; the edge commits each built package
684
- `gtd: building`.
685
-
686
767
  ### Execute
687
768
 
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
- status Print current state, next state, and pending edge actions (no actions, no prompt)
763
-
764
- Options:
765
- --json Output structured JSON instead of plain text
766
- --verbose Show verbose output (thinking deltas, tool events)
767
- --debug Show debug-level internal information
768
- --version, -v Print version and exit
769
- --help, -h Print this help and exit
770
- ```
771
-
772
- `--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
773
- repository-state work — they run outside a repo and in any repo state.
774
-
775
- ## Subcommands
776
-
777
- gtd ships three subcommands: `format`, `review`, and `status`.
778
-
779
- ## Review subcommand
780
-
781
- ```bash
782
- gtd review <target>
783
- ```
784
-
785
- Starts an explicit, on-demand human review of the diff between HEAD and
786
- `merge-base(<target>, HEAD)`. Use this when the automatic review base yields no
787
- diff (idle tree outside a process) or when you want to review against a specific
788
- base regardless of workflow state.
789
-
790
- ### Flow
791
-
792
- 1. `gtd review <target>` computes the diff HEAD adds over
793
- `merge-base(<target>, HEAD)`.
794
- 2. The edge writes an empty anchor commit `gtd: reviewing` (no content — just
795
- the marker).
796
- 3. The **Clean** state writes `REVIEW.md` with the computed diff and emits the
797
- normal review prompt. `--json` is accepted and enables auto-advance mode
798
- (same behavior as the default command).
799
- 4. The normal loop then drives: **Await Review** → **Done** → **Squashing**,
800
- collapsing back to the `gtd: reviewing` anchor commit.
801
-
802
- ### Error handling
803
-
804
- All errors exit with **code 1** and write a message to **stderr**:
805
-
806
- - **Missing target** — `gtd review` with no argument:
807
- `gtd review: missing target argument`
808
- - **Extra arguments** — `gtd review main extra`:
809
- `gtd review: too many arguments — expected one target, got: …`
810
- - **Unresolvable ref** — the target cannot be resolved by git:
811
- `gtd review: cannot resolve ref '<target>': <error message>`
812
- - **Empty diff** — the merge-base diff between `<target>` and HEAD is empty
813
- (nothing to review):
814
- `gtd review: nothing to review (<target> diff is empty after filtering)`
815
-
816
- ## Status subcommand
817
-
818
- ```bash
819
- gtd status
820
- ```
821
-
822
- Pure, read-only introspection. Prints the current machine state, the state the
823
- next real `gtd` run would stop at, and a short summary of the edge actions the
824
- next run would perform. Performs **nothing** (no commit, reset, or file write)
825
- and prints **no prompt** — guaranteed side-effect free.
826
-
827
- ### Fields
828
-
829
- | Field | Description |
830
- | ----------------- | ----------------------------------------------------------------- |
831
- | `state` | Current machine state |
832
- | `nextState` | State the next `gtd` run would stop at, or `null` for edge-only |
833
- | `willAutoAdvance` | `true` when the current state is edge-only (auto-advances on run) |
834
- | `edgeActions` | List of edge actions the next run would perform before prompting |
835
-
836
- ### One-hop semantics
837
-
838
- `status` runs the same read-only gather+resolve the driver's first iteration
839
- does, then reports it without looping or performing.
840
-
841
- - A **prompt-bearing / human / terminal** current state reports itself as
842
- `nextState`. The next run performs any pending edge action, then prompts
843
- there.
844
- - An **edge-only** current state reports `nextState: null` and
845
- `willAutoAdvance: true`, naming the immediate edge action. Because the landing
846
- state after auto-advance depends on side effects (test pass/fail, commits)
847
- that `status` refuses to run, it honestly reports the current state rather
848
- than guessing a landing state. There is **no** multi-hop simulation.
849
-
850
- ### Output
851
-
852
- Default (human-readable) — `building` example:
853
-
854
- ```
855
- State: building
856
- Next state: building (next run prompts here)
857
- Edge actions:
858
- - commit pending changes as "gtd: building"
859
- ```
860
-
861
- With `--json` — same example:
862
-
863
- ```json
864
- {
865
- "state": "building",
866
- "nextState": "building",
867
- "willAutoAdvance": false,
868
- "edgeActions": ["commit pending changes as \"gtd: building\""]
869
- }
870
- ```
871
-
872
- Edge-only example (`testing` state):
873
-
874
- ```json
875
- {
876
- "state": "testing",
877
- "nextState": null,
878
- "willAutoAdvance": true,
879
- "edgeActions": ["run the test suite (attempt 1)"]
880
- }
881
- ```
882
-
883
- The JSON envelope contains no `prompt` field — this distinguishes it from the
884
- default `gtd` run and `gtd review` JSON output.
885
-
886
- ### Requirements
887
-
888
- - Must be run from the **repository root** (same cwd guard as other repo
889
- commands).
890
- - Takes **no arguments** — extra args are rejected with an error.
891
-
892
- ## Format subcommand
893
-
894
- `gtd format` formats a markdown file in place:
895
-
896
- ```bash
897
- gtd format <file>
898
- ```
899
-
900
- It uses a bundled prettier with a fixed, gtd-owned config (`parser: "markdown"`,
901
- `printWidth: 80`, `proseWrap: "always"`). The host repo's `.prettierrc` is
902
- **intentionally ignored** — determinism across consumer repos matters more than
903
- local style preferences.
904
-
905
- The grilling and clean prompts instruct the agent to run this command after
906
- every edit to `TODO.md` or `REVIEW.md`, so those files stay consistently
907
- formatted regardless of the host project's toolchain.
908
-
909
- ### Error handling
910
-
911
- All errors exit with **code 1** and write a message to **stderr**:
912
-
913
- - **Missing path** — `gtd format` with no argument:
914
- `gtd format: missing file path argument`
915
- - **Extra arguments** — `gtd format a.md b.md`:
916
- `gtd format: too many arguments — expected one path, got: …`
917
- - **Non-markdown file** — any extension other than `.md` or `.markdown`
918
- (case-insensitive):
919
- `gtd format: <file> is not a markdown file (expected .md or .markdown)`
920
- - **File not found** — the path does not exist:
921
- `gtd: skipped formatting <file>: not found`
922
-
923
- > [!NOTE] Upgrading gtd may reflow existing `TODO.md` files if the bundled
924
- > prettier major version changes.
769
+ Execution is **one package per cycle**. `gtd next` selects the single next
770
+ package itself, names it in the prompt, and inlines its task files' full
771
+ contents the agent never browses `.gtd/` or picks a package itself. A single
772
+ cycle:
773
+
774
+ 1. Spawn parallel execution-model workers for all tasks in the selected package.
775
+ 2. Leave all changes **uncommitted**. Do not commit, do not delete the package
776
+ directory, do not run tests.
777
+ 3. Finish the turn with `gtd step-agent` — the next hop's edge action commits
778
+ the work (`gtd(agent): building`) and runs `testCommand` to verify it.
779
+
780
+ ## Upgrading from v1 (BREAKING CHANGE)
781
+
782
+ v2 ships as a **major** semantic-release bump (`2.0.0`) so the binary and the
783
+ loop-driving text (this README, `skills/loop/SKILL.md`) can never skew against
784
+ each other. There is **no backward compatibility with the v1 command surface**:
785
+ the single mutating `gtd` command, marker/sentinel files, the `autoAdvance` JSON
786
+ field, and the `gtd: transport` handoff commit are all gone. `gtd` bare now
787
+ errors rather than driving a loop; use `gtd step-agent` / `gtd next` /
788
+ `gtd step` instead.
789
+
790
+ **Commit-history compatibility is one-way.** Any repo with v1-taxonomy history
791
+ in it (`gtd: new task`, `gtd: grilling`, `gtd: transport`, a bare
792
+ `gtd: reviewing` with no hash, …) upgrades cleanly: those subjects fall outside
793
+ v2's closed turn/routing grammar and parse as inert **boundary commits** they
794
+ are never mistaken for v2 workflow state and never error.
795
+
796
+ **Finish or clean up any in-flight v1 cycle first.** If a repo has an
797
+ **in-progress** v1 cycle steering files present (root-level `TODO.md`,
798
+ `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, or `.gtd/`) whose HEAD carries v1-only
799
+ commit subjects — the v2 binary does not know how to resume it: v1 steering
800
+ files have no v2 turn commit backing them, so a cold v2 invocation on that tree
801
+ can land in an unrecognized state. Either finish the v1 cycle to a clean
802
+ boundary with your existing v1 binary before upgrading, or manually clean up
803
+ (remove the steering files / `.gtd/`, commit the result) so the upgrade starts
804
+ from a plain boundary HEAD.
805
+
806
+ **Steering files moved into `.gtd/`.** Earlier v2 builds kept `TODO.md`,
807
+ `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, `HEALTH.md`, and `SQUASH_MSG.md` at the
808
+ repository root; they now live under `.gtd/`. Upgrade at a clean boundary (idle,
809
+ post-squash): a repo at rest needs nothing. Mid-cycle repos should either finish
810
+ the cycle on the old build first or move the root-level steering files into
811
+ `.gtd/` by hand and commit. History classification is backward-compatible — the
812
+ counter folds recognize both the old root paths and the new `.gtd/` paths in
813
+ existing commits.
814
+
815
+ **Re-copy the loop skill.** If you vendor `skills/loop/` into a consuming repo
816
+ or agent harness, upgrading the `gtd` binary also means re-copying that skill
817
+ from this release the v1 skill text still describes the old single-command
818
+ loop and will drive the new binary incorrectly.
819
+
820
+ For maintainers: this repo releases via `semantic-release` reading Conventional
821
+ Commits, and needs **no config change** for a major bump — but the release
822
+ commit/PR **must carry a `BREAKING CHANGE:` footer** (or a `!` after the type)
823
+ for `@semantic-release/commit-analyzer` to compute `2.0.0` rather than a
824
+ minor/patch bump.
925
825
 
926
826
  ## Development
927
827
 
@@ -929,9 +829,10 @@ All errors exit with **code 1** and write a message to **stderr**:
929
829
  npm install
930
830
  npm run dev # run from source, no build (node dev/run.mjs)
931
831
  npm run build # tsup → dist/gtd.bundle.mjs
932
- npm test # vitest unit tests (the pure resolver) --project unit
832
+ npm test # format:check, typecheck, lint, unit + e2e tests, fallow
833
+ npm run test:unit # vitest unit tests (the pure resolver) — --project unit
933
834
  npm run test:e2e # gherkin e2e via vitest + quickpickle — --project e2e
934
- npm run test:mutation # StrykerJS mutation testing
835
+ npm run test:mutation # StrykerJS mutation testing (manual only, ~2 min)
935
836
  npm run typecheck
936
837
  npm run lint
937
838
  ```
@@ -939,29 +840,20 @@ npm run lint
939
840
  ### Pre-commit hook
940
841
 
941
842
  A pre-commit hook is installed automatically via the `prepare` script when you
942
- run `npm install` on a fresh clone — no manual setup needed.
943
-
944
- The hook runs [lint-staged](https://github.com/lint-staged/lint-staged) with
843
+ run `npm install` on a fresh clone — no manual setup needed. The hook runs
844
+ [lint-staged](https://github.com/lint-staged/lint-staged) with
945
845
  [Prettier](https://prettier.io/), formatting every staged file before each
946
- commit:
947
-
948
- ```
949
- prettier --ignore-unknown --write
950
- ```
951
-
952
- This mirrors the `format:check` step enforced in CI (`prettier --check .`),
953
- keeping committed code consistently formatted without requiring a separate
954
- manual format pass.
846
+ commit (`prettier --ignore-unknown --write`), mirroring the `format:check` step
847
+ enforced in CI (`prettier --check .`).
955
848
 
956
849
  ### Prompt templates
957
850
 
958
851
  Each prompt-bearing state has a self-contained Eta template in
959
- `src/prompts/*.md` that owns its full prompt — header, context, body, and tail.
960
- Shared fragments live as partials in `src/prompts/partials/`: `header`, the
961
- context renderers (`context`, `package`, `diff`, `feedback`), and three tail
962
- variants (`auto-advance`, `neutral`, `stop`). Templates compose them via Eta's
963
- `<%~ include("@name", { … }) %>` syntax; dynamic values such as the resolved
964
- model string are injected as Eta variables (`<%= model %>`).
852
+ `src/prompts/*.md` that owns its full prompt — header, context, and body. Shared
853
+ fragments live as partials in `src/prompts/partials/`: `header`, the context
854
+ renderers (`diff`, `feedback`, `package`), and the single `agent-turn` tail
855
+ partial (the pinned "Finish your turn by running `gtd step-agent`. Then run
856
+ `gtd next` …" loop-closing instructions).
965
857
 
966
858
  At module load, `src/Prompt.ts` registers every template on a single `new Eta()`
967
859
  instance via `loadTemplate`. `readFile` and `resolvePath` are nulled afterward
@@ -971,16 +863,17 @@ bundle carries no runtime `fs` dependency.
971
863
  `buildPrompt(result, resolveModel?, output?)` selects the state's template,
972
864
  builds a view-model (model string, tail partial name, context), renders it,
973
865
  collapses runs of three or more blank lines to two, and ensures exactly one
974
- trailing newline.
866
+ trailing newline. It throws for the five states that render no prompt at all
867
+ (`testing`, `planning`, `close-package`, `done`, `health-check`) — those are
868
+ performed entirely by the edge.
975
869
 
976
870
  `npm run dev` runs `src/main.ts` directly via Node's native TypeScript
977
871
  type-stripping (requires Node 22.6+). It registers `dev/hooks.mjs`, which fills
978
872
  the two gaps the tsup build otherwise covers: resolving `./Foo.js` specifiers to
979
873
  the on-disk `./Foo.ts`, and importing `*.md` prompt files as text. Pass CLI args
980
- after `--`, e.g. `npm run dev -- format <file>`. The helpers live in `dev/`
981
- rather than `scripts/` because tsup wipes `dist/` (`clean: true`) on build.
874
+ after `--`, e.g. `npm run dev -- format <file>`.
982
875
 
983
- The decision core (`src/Machine.ts`) is pure and IO-free, so the whole 17-state
876
+ The decision core (`src/Machine.ts`) is pure and IO-free, so the whole 16-state
984
877
  ladder and both counter folds are trivially unit-testable in isolation; all
985
878
  git/filesystem IO is confined to the edge (`src/Events.ts`).
986
879
 
@@ -989,8 +882,10 @@ binary via the `bin` field in `package.json`.
989
882
 
990
883
  ### Mutation testing
991
884
 
992
- Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min).
993
- The single `stryker.config.json` mutates six core files:
885
+ Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min)
886
+ never run it as part of routine development; it is a deliberate,
887
+ manually-triggered check. The single `stryker.config.json` mutates six core
888
+ files:
994
889
 
995
890
  ```
996
891
  src/Machine.ts src/Prompt.ts src/Config.ts
@@ -998,56 +893,9 @@ src/Format.ts src/State.ts src/Events.ts
998
893
  ```
999
894
 
1000
895
  `src/Git.ts` is excluded: the Cucumber harness stubs git at the Effect boundary,
1001
- so Git.ts mutants have zero in-memory coverage. Measuring its post-refactor
1002
- Live-tier kill rate is a follow-up before re-including it.
1003
-
1004
- **`process.chdir()` gotcha (resolved).** `@stryker-mutator/vitest-runner`
1005
- hardcodes `pool: 'threads'` internally, and `process.chdir()` is unsupported in
1006
- worker threads. Before the cwd refactor (package 01), four test files
1007
- (`Events.test.ts`, `Git.test.ts`, `Config.test.ts`, `TestRunner.test.ts`) had to
1008
- be excluded from all Stryker runs. The refactor eliminated those calls, letting
1009
- all four files rejoin the run.
1010
-
1011
- Two additional notes: `vitest.related` is disabled for feature-file runs because
1012
- feature files don't import source files directly (Stryker's coverage-based
1013
- filtering would assign zero tests to every mutant). Compile-error mutants are
1014
- counted as kills by the TypeScript checker — they represent real signal, not a
1015
- configuration problem.
1016
-
1017
- Run `npm run test:mutation` after making changes to the mutated files to check
1018
- whether surviving mutants increased. The HTML report lands in
1019
- `reports/mutation/mutation.html` (git-ignored).
1020
-
1021
- ### Mutation testing
1022
-
1023
- Run mutation testing on-demand with `npm run test:mutation` (StrykerJS, ~2 min).
1024
- The single `stryker.config.json` mutates six core files:
896
+ so `Git.ts` mutants have zero in-memory coverage.
1025
897
 
1026
- ```
1027
- src/Machine.ts src/Prompt.ts src/Config.ts
1028
- src/Format.ts src/State.ts src/Events.ts
1029
- ```
1030
-
1031
- `src/Git.ts` is excluded: the Cucumber harness stubs git at the Effect boundary,
1032
- so Git.ts mutants have zero in-memory coverage. Measuring its post-refactor
1033
- Live-tier kill rate is a follow-up before re-including it.
1034
-
1035
- **`process.chdir()` gotcha (resolved).** `@stryker-mutator/vitest-runner`
1036
- hardcodes `pool: 'threads'` internally, and `process.chdir()` is unsupported in
1037
- worker threads. Before the cwd refactor (package 01), four test files
1038
- (`Events.test.ts`, `Git.test.ts`, `Config.test.ts`, `TestRunner.test.ts`) had to
1039
- be excluded from all Stryker runs. The refactor eliminated those calls, letting
1040
- all four files rejoin the run.
1041
-
1042
- Two additional notes: `vitest.related` is disabled for feature-file runs because
1043
- feature files don't import source files directly (Stryker's coverage-based
1044
- filtering would assign zero tests to every mutant). Compile-error mutants are
1045
- counted as kills by the TypeScript checker — they represent real signal, not a
1046
- configuration problem.
1047
-
1048
- Run `npm run test:mutation` after making changes to the mutated files to check
1049
- whether surviving mutants increased. The HTML report lands in
1050
- `reports/mutation/mutation.html` (git-ignored).
898
+ The HTML report lands in `reports/mutation/mutation.html` (git-ignored).
1051
899
 
1052
900
  ## Releasing
1053
901