@pmelab/gtd 9.7.0 → 9.8.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
@@ -85,34 +85,33 @@ gtd is a small **pattern machine**: named states, each awaiting one actor and
85
85
  carrying one piece of content (a script, a prompt, a message, or a squash commit
86
86
  template), with an ordered set of change-patterns routing to the next state.
87
87
 
88
- The loop is one beat, repeated: run `gtd status --json` and dispatch on `kind` —
88
+ The loop is one beat, repeated: run `gtd next --json` and dispatch on `kind` —
89
89
  `"message"` means it's a human's move (stop and hand off, unless it's the run's
90
90
  opening beat, which the human triggered by re-running the driver: land that one,
91
91
  since changing nothing is itself a declared outcome at some gates); `"capture"`
92
92
  means a human gate the human already acted on (land it immediately); `"script"`
93
93
  means the driver runs `gtd next`'s own plain-text output itself, then lands it;
94
94
  `"prompt"` means feed `gtd next`'s output to your agent — using the accompanying
95
- `session.id`/`session.resume` fields off `gtd status --json` to continue or
96
- start that agent conversation (see "Driving the loop" below) — then run
97
- `gtd land` once it's done. gtd itself never executes anything — the driver owns
98
- running scripts. Every `gtd next`/ `gtd status` call is strictly mutation-free,
99
- safe to poll or peek at any time: `session.id`/`session.resume` are DERIVED,
100
- never stored, so looking is free — nothing distinguishes a peek from a dispatch,
101
- and there is no separate claiming form at all. A `prompt` beat whose turn
102
- changes nothing still lands: `gtd land` commits an EMPTY `gtd(<actor>): <state>`
103
- attempt instead of silently doing nothing, so the fruitless dispatch is visible
104
- in history rather than invisible. `"kind": "stalled"` is derived from that
105
- history — HEAD is an empty attempt at the resting state and the tree is clean —
106
- so every `gtd status --json` call reports it, and it stays reported on a repeat
107
- (there's no marker to consume) until something actually changes. The fix for a
108
- repeated stall is either a better prompt, a `retry:` cap on the state that
109
- redirects to an escalation state after N fruitless attempts, or — if the state
110
- can legitimately finish with nothing to change — declaring a `C` (clean-tree)
111
- pattern on it.
95
+ `session.id`/`session.resume` fields off `gtd next --json` to continue or start
96
+ that agent conversation (see "Driving the loop" below) — then run `gtd land`
97
+ once it's done. gtd itself never executes anything — the driver owns running
98
+ scripts. Every `gtd next` call is strictly mutation-free, safe to poll or peek
99
+ at any time: `session.id`/`session.resume` are DERIVED, never stored, so looking
100
+ is free — nothing distinguishes a peek from a dispatch, and there is no separate
101
+ claiming form at all. A `prompt` beat whose turn changes nothing still lands:
102
+ `gtd land` commits an EMPTY `gtd(<actor>): <state>` attempt instead of silently
103
+ doing nothing, so the fruitless dispatch is visible in history rather than
104
+ invisible. `"kind": "stalled"` is derived from that history — HEAD is an empty
105
+ attempt at the resting state and the tree is clean — so every `gtd next --json`
106
+ call reports it, and it stays reported on a repeat (there's no marker to
107
+ consume) until something actually changes. The fix for a repeated stall is
108
+ either a better prompt, a `retry:` cap on the state that redirects to an
109
+ escalation state after N fruitless attempts, or — if the state can legitimately
110
+ finish with nothing to change — declaring a `C` (clean-tree) pattern on it.
112
111
 
113
112
  An `on` edge may also carry a short imperative `action` (e.g. `Accept plan`)
114
113
  alongside its existing `describe` sentence — a human-facing name for the choice
115
- itself, not just the underlying glob pattern. `gtd status` (plain and `--json`)
114
+ itself, not just the underlying glob pattern. `gtd next` (plain and `--json`)
116
115
  and `gtd visualize`'s diagram and inspector all render the two composed
117
116
  together: the `action` leads when the edge declares one, with the raw pattern
118
117
  (and `describe`) still shown alongside it, so a human choosing between routes
@@ -122,14 +121,14 @@ reads intent first, glob second.
122
121
  to the tree — a hand-edit to real code, a scratch note in some file, anything at
123
122
  all — as a sketch to be finished, never as work to be preserved: there is no
124
123
  fork on which steering file you happen to create, and `idle` has exactly one
125
- outgoing edge, into `unwind`. `.gtd/TODO.md` (the `todoFile` var) is a good
126
- default place to start sketching when you'd rather write a note than touch code
127
- — despite living beside the workflow's own state files, that sketch is your
128
- input for `design.triage` to fold in, never gtd bookkeeping to preserve or
129
- ignore. `unwind` reverts that whole diff back out of your working tree
130
- (`git revert --no-commit` against the commit it just landed in) before planning
131
- ever starts — your tree is back to exactly what it was, and your intent doesn't
132
- disappear, it survives in history for `design.triage` to read.
124
+ outgoing edge, into `unwind`. `.gtd/TODO.md` is a good default place to start
125
+ sketching when you'd rather write a note than touch code — despite living beside
126
+ the workflow's own state files, that sketch is your input for `design.triage` to
127
+ fold in, never gtd bookkeeping to preserve or ignore. `unwind` reverts that
128
+ whole diff back out of your working tree (`git revert --no-commit` against the
129
+ commit it just landed in) before planning ever starts — your tree is back to
130
+ exactly what it was, and your intent doesn't disappear, it survives in history
131
+ for `design.triage` to read.
133
132
 
134
133
  From there, `start-gate.check` runs your test suite on the tree as it now stands
135
134
  — which, thanks to the unwind, is simply your repo's own baseline. The rule is
@@ -223,14 +222,8 @@ rather than sitting beside it) — an actionable round leaves that identity
223
222
  entirely, so it starts a fresh session like any other process. A comment is what
224
223
  asks for changes; landing with no comment signs off, whatever the boxes say,
225
224
  which collapses the whole process into one commit (a **squash finale** whose
226
- message an agent drafts). Deleting `.gtd/REVIEW.md` is refused, wherever the
227
- review doc lives: repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md` at
228
- the repo root) changes nothing about that refusal, since it only asks whether
229
- the step's diff deletes the file. The exact-path exemption issue #128 fixed
230
- still matters elsewhere, though: the `deciding` state's own classification and
231
- the feedback-progress guard both exclude the state's own `file:` by exact path,
232
- not merely a `.gtd/` prefix, so your own edit to a relocated steering file is
233
- never mistaken for a code comment.
225
+ message an agent drafts). Deleting `.gtd/REVIEW.md` is refused — the guard only
226
+ asks whether the step's diff deletes the file.
234
227
 
235
228
  A second entry, the same review tail's own direct entry point —
236
229
  `gtd --entry review-gate.check --var reviewBase=<commitish>` starts a brand new
@@ -263,27 +256,9 @@ to target a state.
263
256
  Every agent state routes its model through two `vars` tiers — `plannerModel`
264
257
  (heavier planning and review) and `coderModel` (the coding turns) — so you can
265
258
  repoint the models globally in one place (a `vars:` edit or a `GTD_PLANNERMODEL`
266
- override) instead of per state. Steering-file path vars (`todoFile`,
267
- `feedbackFile`, `reviewFile`, …) work the same way, and propagate to the `on`
268
- patterns that route on them too — a repointed path var actually reroutes the
269
- machine, not just the templates that read/write the file. `todoFile` (default
270
- `.gtd/TODO.md`, `idle`'s own `file:` hint) is the one exception: it's the only
271
- per-file var gtd never writes and never reads, since it names your own sketch
272
- pad, not a file any state produces. A separate `stateDir` var (default `.gtd`)
273
- names only where the check scripts keep their own scratch/bookkeeping,
274
- independent of the per-file vars — relocate one steering file without touching
275
- it. The workflow declares its plumbing directory once, at the top level of the
276
- `workflow:` value (`stateDir: <%= it.vars.stateDir %>` in the bundled template),
277
- rendered from that same `stateDir` var — this is what the engine itself reads to
278
- tell gtd's own bookkeeping apart from your code (e.g. the review window's revert
279
- pathspec, the step guards' code-vs-plumbing check), not just a value the
280
- templates happen to share. The rendered value is constrained: it must name a
281
- directory inside the repository — not the repo root, not an absolute path, and
282
- not a path that escapes the repository via `..` — and it must be spelled
283
- canonically: no `.` and no empty path segments (`a/./state` or `a//state` are
284
- rejected, not rewritten), though a leading `./` and a trailing `/` are accepted
285
- — or the next `gtd next`/`gtd status`/`gtd land` fails loudly with that message,
286
- rather than silently excluding the whole tree from the review window's revert.
259
+ override) instead of per state. Every steering file the bundled workflow reads
260
+ or writes lives at a fixed path under `.gtd/`; `testCommand`, `plannerModel`,
261
+ `coderModel`, and `reviewBase` are the only vars left to tune.
287
262
 
288
263
  To inspect or change the machine itself, see [Configuration](#configuration) —
289
264
  the workflow is just `.gtdrc` config.
@@ -408,11 +383,11 @@ Options:
408
383
 
409
384
  ### Plain output is not a parsing surface
410
385
 
411
- `gtd next`'s plain encoding (and `gtd status`'s own) is for a human, or a driver
412
- that merely displays it — never for scraping. Parsing lives in `--json`/`--sh`,
413
- both of which read from the exact same field set (`gtd install`'s briefing has
414
- the full reference); anything that greps, cuts, or `awk`s plain text is
415
- unsupported, and its shape may change across releases with no warning.
386
+ `gtd next`'s plain encoding is for a human, or a driver that merely displays it
387
+ — never for scraping. Parsing lives in `--json`/`--sh`, both of which read from
388
+ the exact same field set (`gtd install`'s briefing has the full reference);
389
+ anything that greps, cuts, or `awk`s plain text is unsupported, and its shape
390
+ may change across releases with no warning.
416
391
 
417
392
  ### Exit codes
418
393
 
@@ -480,7 +455,7 @@ command are all usage errors too — landing and entering are different verbs, s
480
455
  `--model`, `--model` without `--cost`, or `--cost`/`--model` on any command
481
456
  other than `gtd land` are all usage errors.
482
457
 
483
- ### `gtd status`'s `Next:`/`next`
458
+ ### `gtd next`'s `Next:`/`next`
484
459
 
485
460
  Both plain and `--json` output include a headline preview of what would happen
486
461
  next: the first declared `on` edge whose pattern matches the pending changes AS
@@ -505,11 +480,11 @@ prompt/script alongside a message about why it stopped. `gtd visualize` is the
505
480
  one exception worth knowing: it flushes its served-URL line immediately, before
506
481
  blocking on `Ctrl-C`, since a flush-on-success would never otherwise fire.
507
482
 
508
- Any invocation that carries `--json` (valid only for `gtd status` — every other
509
- command usage-errors on it) reports a failure as a machine-readable envelope on
510
- **stderr** — including the scope violation itself, so a driver that always adds
511
- `--json` still gets a parseable envelope on every failure, not only
512
- `gtd status`'s own:
483
+ Any invocation that carries `--json` (valid only for `gtd next`/`gtd land` —
484
+ every other command usage-errors on it) reports a failure as a machine-readable
485
+ envelope on **stderr** — including the scope violation itself, so a driver that
486
+ always adds `--json` still gets a parseable envelope on every failure, not only
487
+ `gtd next`'s/`gtd land`'s own:
513
488
 
514
489
  ```json
515
490
  { "state": "error", "prompt": "<message>" }
@@ -592,46 +567,70 @@ not of the loop itself; see
592
567
  below for a worked example.
593
568
 
594
569
  A workflow state can declare an optional `label:` — a human-readable display
595
- name surfaced in `gtd status --json`/plain `gtd status`. The driver uses it for
596
- its per-beat progress lines; an outer wrapper (a terminal multiplexer, a
597
- notifier) can use it the same way.
570
+ name surfaced in `gtd next --json`/plain `gtd next`. The driver uses it for its
571
+ per-beat progress lines; an outer wrapper (a terminal multiplexer, a notifier)
572
+ can use it the same way.
573
+
574
+ A machine may also declare `system:` — like `model:`, stamped once at the
575
+ machine level onto every one of that machine's own `prompt` states, never
576
+ authored on an individual state. It is passed to the agent CLI as (in the
577
+ reference driver's case) `--system-prompt`, which **replaces** the harness's own
578
+ default system prompt outright rather than appending to it (contrast with an
579
+ `--append-system-prompt`-shaped flag) — so a machine declaring `system:` loses
580
+ not only the harness's own tool-use instructions but also its dynamic per-turn
581
+ sections: current working directory, environment info, memory-path information,
582
+ git status. A workflow author reaching for `system:` for the first time is
583
+ therefore writing a complete replacement system prompt, not a tweak on top of
584
+ the harness's own. The scoping is machine-level for the same reason memory is
585
+ machine-scoped below: a machine is the unit of conversational identity, so its
586
+ system prompt — like its model tier — is one property of that identity, constant
587
+ across every turn of the one resumed session, never a per-state override. Like
588
+ `model:`/`file:`, a `system:` value prefixed `./` or `../` is inlined from the
589
+ declaring config file's own directory at compile time — for a user's own
590
+ `.gtdrc` `workflow:` config only; the bundled template ships no filesystem
591
+ references at all, since it has to work inside a single-file build. The bundled
592
+ default template ships six such personas already, one per prompt-bearing machine
593
+ — `designPersona`, `architectPersona`, `reviewerPersona`, `specReviewerPersona`,
594
+ `builderPersona`, `finisherPersona` — and, like any other bundled var, each is
595
+ overridable through a top-level `.gtdrc` `vars:` key or a `GTD_<NAME>`-style
596
+ environment variable (e.g. `GTD_DESIGNPERSONA`) — gtd's existing, generic
597
+ vars-override mechanism, nothing new.
598
598
 
599
599
  Memory is **entry-scoped to a machine**, not a state-authored label: each
600
600
  machine instance (a node in the `machines:` tree, e.g. `build`, `build.health`,
601
601
  `packages.item`, `packages.item.health`) owns its own conversational scope, and
602
- a `prompt`-content state's `memory` key — surfaced in `gtd status --json`'s
603
- `memory` field, and as a `Memory: <key>` line in plain `gtd status` — is
604
- computed, never authored, as `<scope>#<hash7>`: `<scope>` is that machine
605
- instance's dotted path (the root instance is shown as `root`), and `<hash7>`
606
- anchors to the commit the CURRENT unbroken entry into that scope started FROM.
607
- Entering a **descendant** scope (e.g. dipping from `build` into `build.health`)
608
- does not break the parent's unbroken run — a full agent turn in a nested child
609
- machine, then back to the parent, still resumes the SAME parent conversation;
610
- entering a **sibling or unrelated** scope does start a fresh one. The bundled
611
- template's `build.review` (the human review tail) is a worked example: it is
612
- nested INSIDE `build` (the builder's own machine) so that a
613
- `gtd --entry fix-precheck` run — `build.fix` -> `build.health.check` ->
614
- `build.review.*` -> `build.squashing` — stays inside one subtree, letting
615
- `build.squashing` resume the SAME session that made the fixes instead of a
616
- root-level sibling forcing it to re-derive the range from scratch on every pass
617
- through the tail. (An actionable review round breaks the run on purpose instead
618
- — it leaves `build` entirely through a root-level `re-unwind` state and a full
619
- re-plan, since a hand-edit made during review is a sketch to reconsider, not a
620
- fix to build on.) Two instances of the same reusable machine (e.g.
621
- `build.health` and `packages.item.health`, both instantiating `healthGate`) get
622
- different scopes and so never share a key, even though they're the "same shaped"
623
- machine. One consequence is a structural guarantee: **a reviewer's turn never
624
- resumes an implementer's session, and vice versa** — a reviewer machine and the
625
- implementer machine it reviews are always different instances with different
626
- scopes.
602
+ a `prompt`-content state's `memory` key — surfaced in `gtd next --json`'s
603
+ `memory` field, and as a `Memory: <key>` line in plain `gtd next` — is computed,
604
+ never authored, as `<scope>#<hash7>`: `<scope>` is that machine instance's
605
+ dotted path (the root instance is shown as `root`), and `<hash7>` anchors to the
606
+ commit the CURRENT unbroken entry into that scope started FROM. Entering a
607
+ **descendant** scope (e.g. dipping from `build` into `build.health`) does not
608
+ break the parent's unbroken run — a full agent turn in a nested child machine,
609
+ then back to the parent, still resumes the SAME parent conversation; entering a
610
+ **sibling or unrelated** scope does start a fresh one. The bundled template's
611
+ `build.review` (the human review tail) is a worked example: it is nested INSIDE
612
+ `build` (the builder's own machine) so that a `gtd --entry fix-precheck` run —
613
+ `build.fix` -> `build.health.check` -> `build.review.*` -> `build.squashing` —
614
+ stays inside one subtree, letting `build.squashing` resume the SAME session that
615
+ made the fixes instead of a root-level sibling forcing it to re-derive the range
616
+ from scratch on every pass through the tail. (An actionable review round breaks
617
+ the run on purpose instead — it leaves `build` entirely through a root-level
618
+ `re-unwind` state and a full re-plan, since a hand-edit made during review is a
619
+ sketch to reconsider, not a fix to build on.) Two instances of the same reusable
620
+ machine (e.g. `build.health` and `packages.item.health`, both instantiating
621
+ `healthGate`) get different scopes and so never share a key, even though they're
622
+ the "same shaped" machine. One consequence is a structural guarantee: **a
623
+ reviewer's turn never resumes an implementer's session, and vice versa** — a
624
+ reviewer machine and the implementer machine it reviews are always different
625
+ instances with different scopes.
627
626
 
628
627
  `gtd` itself stores NOTHING to make this work: `session.id` is
629
628
  `UUIDv5(<fixed gtd namespace>, <memory key>)` — a deterministic hash of the
630
629
  computed `<scope>#<hash7>` key above — so the same scope-run always re-derives
631
630
  the exact same id, and there is no table, no file, no write to keep in sync.
632
631
  `session.resume` is `true` iff a prior `prompt` turn already landed within that
633
- same scope-run. Because nothing is written, calling `gtd status --json` twice in
634
- a row — a driver's own opening peek, a status poll, a curious human — derives
632
+ same scope-run. Because nothing is written, calling `gtd next --json` twice in a
633
+ row — a driver's own opening peek, a status poll, a curious human — derives
635
634
  IDENTICAL `session.id`/`session.resume` values both times, since there is
636
635
  nothing to poison: looking is free, and there is no separate claiming form to
637
636
  protect. The per-scope survival story (a child machine's own excursion doesn't
@@ -792,7 +791,7 @@ invokes that script with.
792
791
  carry one — there is no window to reopen after either, so their printed
793
792
  artifact is the required half alone, with no trailing comment/subshell at all.
794
793
 
795
- `gtd status --json` carries one more field worth a custom driver's attention:
794
+ `gtd next --json` carries one more field worth a custom driver's attention:
796
795
 
797
796
  - **`log`** — the per-worktree loop log path, always present. It's derived from
798
797
  the worktree's own git dir, so two worktrees looping concurrently never share
@@ -843,16 +842,16 @@ advance instead of settling.
843
842
 
844
843
  ### Drivers other than sh
845
844
 
846
- The protocol above is JSON in (from `gtd status --json` alone), subprocesses out
847
- — sh is one convenient shape, not the only one. A **program** parses
848
- `gtd status --json`, switches on `kind`, and runs `gtd next`'s (plain-text)
849
- output and `gtd land`'s (POSIX sh) output as subprocesses — no sh anywhere in
850
- it. A **human** runs plain `gtd next` (there is no JSON form of it at all), does
851
- what it says, and pastes `gtd land | sh`: plain-text output exists for exactly
852
- this, printing the combined script ready to paste. An **agent** gets
853
- `gtd install` as its instructions — the same protocol, in a form built to be
854
- pasted into a context window rather than read. A **CI job** is the program case
855
- with the `prompt` arm pointed at a headless agent CLI, and
845
+ The protocol above is JSON in (from `gtd next --json` alone), subprocesses out —
846
+ sh is one convenient shape, not the only one. A **program** parses
847
+ `gtd next --json`, switches on `kind`, and runs `gtd next`'s (plain-text) output
848
+ and `gtd land`'s (POSIX sh) output as subprocesses — no sh anywhere in it. A
849
+ **human** runs plain `gtd next` (there is no JSON form of it at all), does what
850
+ it says, and pastes `gtd land | sh`: plain-text output exists for exactly this,
851
+ printing the combined script ready to paste. An **agent** gets `gtd install` as
852
+ its instructions — the same protocol, in a form built to be pasted into a
853
+ context window rather than read. A **CI job** is the program case with the
854
+ `prompt` arm pointed at a headless agent CLI, and
856
855
  `kind: "message"`/`kind: "stalled"` mapped onto "stop and report".
857
856
 
858
857
  ### A complete minimal driver
@@ -914,8 +913,9 @@ while :; do
914
913
  # macOS, and POSIX guarantees only 4 KB, ARG_MAX), and a diff crosses
915
914
  # that far sooner than you'd expect.
916
915
  agent_turn() { printf '%s' "$gtd_content" | claude -p "$1" "$gtd_session_id" \
917
- ${gtd_model:+--model "$gtd_model"} --dangerously-skip-permissions \
918
- >>"$gtd_log" 2>&1; }
916
+ ${gtd_model:+--model "$gtd_model"} \
917
+ ${gtd_system:+--system-prompt "$gtd_system"} \
918
+ --dangerously-skip-permissions >>"$gtd_log" 2>&1; }
919
919
  if [ "${gtd_session_resume:-}" = true ]
920
920
  then agent_turn --resume || agent_turn --session-id
921
921
  else agent_turn --session-id || agent_turn --resume
@@ -924,8 +924,16 @@ while :; do
924
924
  while [ -n "${gtd_validate:-}" ] && ! fix="$(sh -c "$gtd_validate" 2>&1)"; do
925
925
  n=$((n + 1)) && [ "$n" -gt 3 ] && { printf '%s\n' "$fix" >&2; exit 1; }
926
926
  # $fix IS the fix prompt, verbatim — piped for the same reason as
927
- # $gtd_content above
927
+ # $gtd_content above. Whether `claude --resume` re-applies the
928
+ # original session's model/system prompt is a harness detail gtd
929
+ # cannot verify from outside, so this passes the identical
930
+ # $gtd_model/$gtd_system on both calls rather than assume it does —
931
+ # otherwise this fix turn might silently fall back to Claude Code's
932
+ # own defaults while the turn that produced the file ran under the
933
+ # workflow's own model and persona.
928
934
  printf '%s' "$fix" | claude -p --resume "$gtd_session_id" \
935
+ ${gtd_model:+--model "$gtd_model"} \
936
+ ${gtd_system:+--system-prompt "$gtd_system"} \
929
937
  --dangerously-skip-permissions >>"$gtd_log" 2>&1
930
938
  done ;;
931
939
  esac
@@ -960,12 +968,13 @@ re-invocation authored and which therefore lands like any other decision (see
960
968
  not gtd, decides, because "has the human read this gate" is run-scoped knowledge
961
969
  gtd deliberately does not keep); `capture` lands a human's already-made edit
962
970
  outright, no display needed; `script` runs `$gtd_content` in the driver;
963
- `prompt` sends it to the agent over stdin with `$gtd_session_id`/`$gtd_model`
964
- mapped onto the agent's session flags — trying `resume`'s hinted flag first and
965
- falling back to the other on failure, since the session id is derived, not
966
- remembered (see [Driving the loop](#driving-the-loop) above) — and its own
967
- `$gtd_validate` script's output re-prompted verbatim on failure (the driver owns
968
- only the retry cap). Every optional variable (`$gtd_model`, `$gtd_validate`,
971
+ `prompt` sends it to the agent over stdin with
972
+ `$gtd_session_id`/`$gtd_model`/`$gtd_system` mapped onto the agent's session
973
+ flags — trying `resume`'s hinted flag first and falling back to the other on
974
+ failure, since the session id is derived, not remembered (see
975
+ [Driving the loop](#driving-the-loop) above) — and its own `$gtd_validate`
976
+ script's output re-prompted verbatim on failure (the driver owns only the retry
977
+ cap). Every optional variable (`$gtd_model`, `$gtd_system`, `$gtd_validate`,
969
978
  `$gtd_session_resume`, `$gtd_idle`, `$gtd_settled`) is read as `${var:-}` or
970
979
  `${var:+...}` — under `set -u`, the `--sh` document's own `unset` preamble makes
971
980
  an absent field genuinely unset, not empty, so a bare `$gtd_model` would abort
@@ -979,10 +988,24 @@ the reference driver reads once more (a plain `gtd next`) only to DISPLAY that
979
988
  gate's own message, the decision to stop already made from `$gtd_settled`/
980
989
  `$gtd_idle` alone.
981
990
 
991
+ This paste passes `$gtd_system` on argv, and POSIX guarantees only 4 KB of argv
992
+ (`ARG_MAX`) — real systems are far higher (roughly 1 MB on both macOS and
993
+ Linux), and the bundled personas are only a few KB each, so this works
994
+ everywhere in practice. A driver shipping much larger system prompts, or
995
+ targeting a platform sitting at the POSIX floor, should write the string to a
996
+ file and pass that instead: gtd's own contract ends at emitting `gtd_system` as
997
+ a string, and how a driver hands that string to its agent CLI — argv, a temp
998
+ file, or something else — is the driver's own call, since it alone knows its
999
+ platform's argv limit and whether it has a writable temp directory; gtd adds no
1000
+ flag, no file, and no mechanism of its own for this. (The doc-test below only
1001
+ proves this paste parses and runs against a `claude` shim — not that the flag is
1002
+ spelled or placed correctly; that's a `claude --help` check plus one live run,
1003
+ not something the green suite can catch.)
1004
+
982
1005
  ### The self-validation gate
983
1006
 
984
1007
  After an agent turn at a state that declares `file:`+`mode:`, run the script:
985
- either `gtd status --json`'s own embedded `.validate` field (present at every
1008
+ either `gtd next --json`'s own embedded `.validate` field (present at every
986
1009
  `prompt` beat that hands over a validatable file), or, standalone,
987
1010
  `gtd validate`'s own plain-text output — both resolve the exact same script from
988
1011
  one shared resolver. Exit 0 means the file is well-formed — proceed to
@@ -1156,7 +1179,6 @@ workflow:
1156
1179
  <name>:
1157
1180
  format: <shell command> # both optional — {} is the format-only tier
1158
1181
  validate: <shell command>
1159
- stateDir: <string> # optional, an Eta template naming where this workflow keeps its own plumbing (default ".gtd") — the definition-level declaration the engine reads, distinct from the `vars.stateDir` var the bundled template renders it from
1160
1182
  entry:
1161
1183
  default: <machine name> # which machine is the ROOT instance
1162
1184
  machines:
@@ -1181,8 +1203,8 @@ workflow:
1181
1203
  retry:
1182
1204
  max: <number>
1183
1205
  otherwise: <targetState>
1184
- label: <string> # optional, opaque display name passed through `gtd status --json`
1185
- file: <string> # optional, an Eta template naming the state's steering file
1206
+ label: <string> # optional, opaque display name passed through `gtd next --json`
1207
+ file: <string> # optional, an Eta template naming the state's steering file RELATIVE to ".gtd/" — the compiler prepends that directory automatically
1186
1208
  mode: <modeName> # optional, requires "file" — must be declared in `modes:` (qa/review are seeded for you; everything else, including prose, you declare)
1187
1209
  reviewWindow: true # optional — open the review checkout window at rest here
1188
1210
  reviewBase: true # optional — anchor the review window's diff base to this state's most-recent commit
@@ -1202,11 +1224,7 @@ derives a driver's session id).
1202
1224
  The top-level `entry:` key (naming the root machine, `entry.default`) and a
1203
1225
  state's own `entry: true` flag are the same word at two different levels, by
1204
1226
  design: one selects the workflow's root machine, the other opts one state in as
1205
- an extra manual entry point. The top-level `stateDir:` key and the
1206
- `vars.stateDir` var it renders from are the same call: the definition-level
1207
- declaration is what the engine reads (e.g. to tell gtd's own plumbing apart from
1208
- your code), while the var is the knob you actually override — repointing
1209
- `vars.stateDir` moves both.
1227
+ an extra manual entry point.
1210
1228
 
1211
1229
  A workflow is authored as a TREE of reusable, parameterized machines — a
1212
1230
  gate/loop written once and instantiated several times with different `with:`
@@ -1239,8 +1257,8 @@ Besides `it.vars` (below), a `script`/`prompt`/`message`/`commit` template sees:
1239
1257
 
1240
1258
  A template never sees rendered diff CONTENT — no field carries a diff. It names
1241
1259
  a base and leaves the agent to run `git diff <base>` itself; this keeps every
1242
- render cheap (no diff computed on `gtd next`/`gtd status`/`gtd lsp`) and the
1243
- prompt small and cacheable.
1260
+ render cheap (no diff computed on `gtd next`/`gtd lsp`) and the prompt small and
1261
+ cacheable.
1244
1262
 
1245
1263
  Authoring or editing a workflow with a coding agent? `skills/authoring/SKILL.md`
1246
1264
  is the agent-facing contract for producing a valid `workflow:` — the state
@@ -1401,10 +1419,10 @@ top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
1401
1419
  `GTD_STYLEFORMATCONTRACT` environment variable):
1402
1420
 
1403
1421
  - **`styleBlock`** — the voice itself, injected at all seven prompt states that
1404
- generate content, not just three: the free-prose ones — the `packagesDir`
1405
- package files (`architecture.decompose`), `specFeedbackFile`
1406
- (`packages.item.spec.review`), and `commitMsgFile` (`build.squashing`) — plus
1407
- the four machine-parsed states named in the next bullet. Blanking
1422
+ generate content, not just three: the free-prose ones — the `.gtd/packages/`
1423
+ package files (`architecture.decompose`), `.gtd/SPEC_FEEDBACK.md`
1424
+ (`packages.item.spec.review`), and `.gtd/COMMIT_MSG.md` (`build.squashing`) —
1425
+ plus the four machine-parsed states named in the next bullet. Blanking
1408
1426
  `GTD_STYLEBLOCK` strips the voice from all seven, including the machine-parsed
1409
1427
  ones, not only the free-prose three. In short: why density matters before any
1410
1428
  rule, answer-first with no preamble or restatement, blunt and imperative,
@@ -1417,17 +1435,17 @@ top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
1417
1435
  ahead of the role sentence and well before any state-specific format-contract
1418
1436
  text — `styleBlock` first, then `styleFormatContract`, at the four prompt
1419
1437
  states whose output a parser reads: the two `qa`-mode steering files
1420
- (`requirementsFile` at `design.triage`, `architectureFile` at
1421
- `architecture.author`) and the `review`-mode one (`reviewFile` at
1422
- `build.review.reviewing`), plus `requirementsFile` again at
1438
+ (`.gtd/REQUIREMENTS.md` at `design.triage`, `.gtd/ARCHITECTURE.md` at
1439
+ `architecture.author`) and the `review`-mode one (`.gtd/REVIEW.md` at
1440
+ `build.review.reviewing`), plus `.gtd/REQUIREMENTS.md` again at
1423
1441
  `build.review.collecting`, which classifies a review round straight into it.
1424
1442
 
1425
1443
  Three more generated files carry no injected voice, because a script — not an
1426
- agent — writes them: `feedbackFile` (verbatim test-suite output plus a HEAD
1427
- stamp — the tool's content, not gtd's prose), `nextFile` (a bare path, no prose
1428
- to style), and `reviewRawFile` (gtd's own prose, hand-tightened in the voice
1429
- directly in `build.review.deciding`'s script rather than templated in through
1430
- either variable).
1444
+ agent — writes them: `.gtd/FEEDBACK.md` (verbatim test-suite output plus a HEAD
1445
+ stamp — the tool's content, not gtd's prose), `.gtd/NEXT.md` (a bare path, no
1446
+ prose to style), and `.gtd/REVIEW_RAW.md` (gtd's own prose, hand-tightened in
1447
+ the voice directly in `build.review.deciding`'s script rather than templated in
1448
+ through either variable).
1431
1449
 
1432
1450
  ### Lookup and precedence
1433
1451
 
@@ -1502,8 +1520,8 @@ option"/"uncheck this option" code actions on each option — offered anywhere o
1502
1520
  the option's list item, including any wrapped continuation lines, not just its
1503
1521
  own `- [ ]` line — diagnostics for both (live as you edit), and a
1504
1522
  `gtd.openSteeringFile` command that jumps to the current state's steering file —
1505
- including `idle`, whose `todoFile` hint gives the one keybinding an answer even
1506
- before a process has started. The command only names that path — it never
1523
+ including `idle`, whose `.gtd/TODO.md` hint gives the one keybinding an answer
1524
+ even before a process has started. The command only names that path — it never
1507
1525
  stat-checks or creates it — so on a repo that has never run gtd, `.gtd/` may not
1508
1526
  exist yet and editors differ on opening a file whose parent directory is missing
1509
1527
  (an empty buffer that creates it on save vs. refusing the path outright); this