@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 +160 -142
- package/dist/gtd.bundle.mjs +361 -290
- package/package.json +1 -1
- package/schema.json +6 -6
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
|
|
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
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
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`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
|
227
|
-
|
|
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.
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
|
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
|
|
509
|
-
command usage-errors on it) reports a failure as a machine-readable
|
|
510
|
-
**stderr** — including the scope violation itself, so a driver that
|
|
511
|
-
`--json` still gets a parseable envelope on every failure, not only
|
|
512
|
-
`gtd
|
|
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
|
|
596
|
-
|
|
597
|
-
|
|
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
|
|
603
|
-
`memory` field, and as a `Memory: <key>` line in plain `gtd
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
`
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
`
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
|
634
|
-
|
|
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
|
|
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
|
|
847
|
-
|
|
848
|
-
`gtd
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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"}
|
|
918
|
-
|
|
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
|
|
964
|
-
mapped onto the agent's session
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
1243
|
-
|
|
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
|
|
1405
|
-
package files (`architecture.decompose`), `
|
|
1406
|
-
(`packages.item.spec.review`), and `
|
|
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
|
-
(`
|
|
1421
|
-
`architecture.author`) and the `review`-mode one (`
|
|
1422
|
-
`build.review.reviewing`), plus `
|
|
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: `
|
|
1427
|
-
stamp — the tool's content, not gtd's prose), `
|
|
1428
|
-
to style), and `
|
|
1429
|
-
directly in `build.review.deciding`'s script rather than templated in
|
|
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 `
|
|
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
|