@pmelab/gtd 9.7.0 → 9.9.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 +167 -148
- 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
|
|
@@ -166,12 +165,13 @@ check+answer gate shape, again skipping the human stop when nothing is open),
|
|
|
166
165
|
deleting `.gtd/REQUIREMENTS.md` once its content is folded in. Once those are
|
|
167
166
|
settled, `architecture.decompose` is a purely mechanical write-out — **one
|
|
168
167
|
package file per concern**, in the settled order, with no merge/split judgement
|
|
169
|
-
of its own (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
of its own (triage grouped the concerns, and `architecture.author` may already
|
|
169
|
+
have re-merged some of them by file footprint) — handing off to the per-package
|
|
170
|
+
build queue: each package (a set of independent tasks a single build turn fans
|
|
171
|
+
out to parallel subagents) runs its own test loop and a per-package **agentic
|
|
172
|
+
review** that verifies it against its own spec. A package whose work already
|
|
173
|
+
landed (an earlier package's fix turn pulled it in) is not a dead end: the build
|
|
174
|
+
turn records per-criterion evidence in `.gtd/SATISFIED.md` instead of
|
|
175
175
|
implementing anything, and the package still goes through the checks and the
|
|
176
176
|
spec review before closing out. If a queue item ever _does_ dead-end (a build
|
|
177
177
|
turn that authors nothing stalls), the supported recovery is to write that same
|
|
@@ -223,14 +223,8 @@ rather than sitting beside it) — an actionable round leaves that identity
|
|
|
223
223
|
entirely, so it starts a fresh session like any other process. A comment is what
|
|
224
224
|
asks for changes; landing with no comment signs off, whatever the boxes say,
|
|
225
225
|
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.
|
|
226
|
+
message an agent drafts). Deleting `.gtd/REVIEW.md` is refused — the guard only
|
|
227
|
+
asks whether the step's diff deletes the file.
|
|
234
228
|
|
|
235
229
|
A second entry, the same review tail's own direct entry point —
|
|
236
230
|
`gtd --entry review-gate.check --var reviewBase=<commitish>` starts a brand new
|
|
@@ -263,27 +257,9 @@ to target a state.
|
|
|
263
257
|
Every agent state routes its model through two `vars` tiers — `plannerModel`
|
|
264
258
|
(heavier planning and review) and `coderModel` (the coding turns) — so you can
|
|
265
259
|
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.
|
|
260
|
+
override) instead of per state. Every steering file the bundled workflow reads
|
|
261
|
+
or writes lives at a fixed path under `.gtd/`; `testCommand`, `plannerModel`,
|
|
262
|
+
`coderModel`, and `reviewBase` are the only vars left to tune.
|
|
287
263
|
|
|
288
264
|
To inspect or change the machine itself, see [Configuration](#configuration) —
|
|
289
265
|
the workflow is just `.gtdrc` config.
|
|
@@ -408,11 +384,11 @@ Options:
|
|
|
408
384
|
|
|
409
385
|
### Plain output is not a parsing surface
|
|
410
386
|
|
|
411
|
-
`gtd next`'s plain encoding
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
387
|
+
`gtd next`'s plain encoding is for a human, or a driver that merely displays it
|
|
388
|
+
— never for scraping. Parsing lives in `--json`/`--sh`, both of which read from
|
|
389
|
+
the exact same field set (`gtd install`'s briefing has the full reference);
|
|
390
|
+
anything that greps, cuts, or `awk`s plain text is unsupported, and its shape
|
|
391
|
+
may change across releases with no warning.
|
|
416
392
|
|
|
417
393
|
### Exit codes
|
|
418
394
|
|
|
@@ -480,7 +456,7 @@ command are all usage errors too — landing and entering are different verbs, s
|
|
|
480
456
|
`--model`, `--model` without `--cost`, or `--cost`/`--model` on any command
|
|
481
457
|
other than `gtd land` are all usage errors.
|
|
482
458
|
|
|
483
|
-
### `gtd
|
|
459
|
+
### `gtd next`'s `Next:`/`next`
|
|
484
460
|
|
|
485
461
|
Both plain and `--json` output include a headline preview of what would happen
|
|
486
462
|
next: the first declared `on` edge whose pattern matches the pending changes AS
|
|
@@ -505,11 +481,11 @@ prompt/script alongside a message about why it stopped. `gtd visualize` is the
|
|
|
505
481
|
one exception worth knowing: it flushes its served-URL line immediately, before
|
|
506
482
|
blocking on `Ctrl-C`, since a flush-on-success would never otherwise fire.
|
|
507
483
|
|
|
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
|
|
484
|
+
Any invocation that carries `--json` (valid only for `gtd next`/`gtd land` —
|
|
485
|
+
every other command usage-errors on it) reports a failure as a machine-readable
|
|
486
|
+
envelope on **stderr** — including the scope violation itself, so a driver that
|
|
487
|
+
always adds `--json` still gets a parseable envelope on every failure, not only
|
|
488
|
+
`gtd next`'s/`gtd land`'s own:
|
|
513
489
|
|
|
514
490
|
```json
|
|
515
491
|
{ "state": "error", "prompt": "<message>" }
|
|
@@ -592,46 +568,70 @@ not of the loop itself; see
|
|
|
592
568
|
below for a worked example.
|
|
593
569
|
|
|
594
570
|
A workflow state can declare an optional `label:` — a human-readable display
|
|
595
|
-
name surfaced in `gtd
|
|
596
|
-
|
|
597
|
-
|
|
571
|
+
name surfaced in `gtd next --json`/plain `gtd next`. The driver uses it for its
|
|
572
|
+
per-beat progress lines; an outer wrapper (a terminal multiplexer, a notifier)
|
|
573
|
+
can use it the same way.
|
|
574
|
+
|
|
575
|
+
A machine may also declare `system:` — like `model:`, stamped once at the
|
|
576
|
+
machine level onto every one of that machine's own `prompt` states, never
|
|
577
|
+
authored on an individual state. It is passed to the agent CLI as (in the
|
|
578
|
+
reference driver's case) `--system-prompt`, which **replaces** the harness's own
|
|
579
|
+
default system prompt outright rather than appending to it (contrast with an
|
|
580
|
+
`--append-system-prompt`-shaped flag) — so a machine declaring `system:` loses
|
|
581
|
+
not only the harness's own tool-use instructions but also its dynamic per-turn
|
|
582
|
+
sections: current working directory, environment info, memory-path information,
|
|
583
|
+
git status. A workflow author reaching for `system:` for the first time is
|
|
584
|
+
therefore writing a complete replacement system prompt, not a tweak on top of
|
|
585
|
+
the harness's own. The scoping is machine-level for the same reason memory is
|
|
586
|
+
machine-scoped below: a machine is the unit of conversational identity, so its
|
|
587
|
+
system prompt — like its model tier — is one property of that identity, constant
|
|
588
|
+
across every turn of the one resumed session, never a per-state override. Like
|
|
589
|
+
`model:`/`file:`, a `system:` value prefixed `./` or `../` is inlined from the
|
|
590
|
+
declaring config file's own directory at compile time — for a user's own
|
|
591
|
+
`.gtdrc` `workflow:` config only; the bundled template ships no filesystem
|
|
592
|
+
references at all, since it has to work inside a single-file build. The bundled
|
|
593
|
+
default template ships six such personas already, one per prompt-bearing machine
|
|
594
|
+
— `designPersona`, `architectPersona`, `reviewerPersona`, `specReviewerPersona`,
|
|
595
|
+
`builderPersona`, `finisherPersona` — and, like any other bundled var, each is
|
|
596
|
+
overridable through a top-level `.gtdrc` `vars:` key or a `GTD_<NAME>`-style
|
|
597
|
+
environment variable (e.g. `GTD_DESIGNPERSONA`) — gtd's existing, generic
|
|
598
|
+
vars-override mechanism, nothing new.
|
|
598
599
|
|
|
599
600
|
Memory is **entry-scoped to a machine**, not a state-authored label: each
|
|
600
601
|
machine instance (a node in the `machines:` tree, e.g. `build`, `build.health`,
|
|
601
602
|
`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.
|
|
603
|
+
a `prompt`-content state's `memory` key — surfaced in `gtd next --json`'s
|
|
604
|
+
`memory` field, and as a `Memory: <key>` line in plain `gtd next` — is computed,
|
|
605
|
+
never authored, as `<scope>#<hash7>`: `<scope>` is that machine instance's
|
|
606
|
+
dotted path (the root instance is shown as `root`), and `<hash7>` anchors to the
|
|
607
|
+
commit the CURRENT unbroken entry into that scope started FROM. Entering a
|
|
608
|
+
**descendant** scope (e.g. dipping from `build` into `build.health`) does not
|
|
609
|
+
break the parent's unbroken run — a full agent turn in a nested child machine,
|
|
610
|
+
then back to the parent, still resumes the SAME parent conversation; entering a
|
|
611
|
+
**sibling or unrelated** scope does start a fresh one. The bundled template's
|
|
612
|
+
`build.review` (the human review tail) is a worked example: it is nested INSIDE
|
|
613
|
+
`build` (the builder's own machine) so that a `gtd --entry fix-precheck` run —
|
|
614
|
+
`build.fix` -> `build.health.check` -> `build.review.*` -> `build.squashing` —
|
|
615
|
+
stays inside one subtree, letting `build.squashing` resume the SAME session that
|
|
616
|
+
made the fixes instead of a root-level sibling forcing it to re-derive the range
|
|
617
|
+
from scratch on every pass through the tail. (An actionable review round breaks
|
|
618
|
+
the run on purpose instead — it leaves `build` entirely through a root-level
|
|
619
|
+
`re-unwind` state and a full re-plan, since a hand-edit made during review is a
|
|
620
|
+
sketch to reconsider, not a fix to build on.) Two instances of the same reusable
|
|
621
|
+
machine (e.g. `build.health` and `packages.item.health`, both instantiating
|
|
622
|
+
`healthGate`) get different scopes and so never share a key, even though they're
|
|
623
|
+
the "same shaped" machine. One consequence is a structural guarantee: **a
|
|
624
|
+
reviewer's turn never resumes an implementer's session, and vice versa** — a
|
|
625
|
+
reviewer machine and the implementer machine it reviews are always different
|
|
626
|
+
instances with different scopes.
|
|
627
627
|
|
|
628
628
|
`gtd` itself stores NOTHING to make this work: `session.id` is
|
|
629
629
|
`UUIDv5(<fixed gtd namespace>, <memory key>)` — a deterministic hash of the
|
|
630
630
|
computed `<scope>#<hash7>` key above — so the same scope-run always re-derives
|
|
631
631
|
the exact same id, and there is no table, no file, no write to keep in sync.
|
|
632
632
|
`session.resume` is `true` iff a prior `prompt` turn already landed within that
|
|
633
|
-
same scope-run. Because nothing is written, calling `gtd
|
|
634
|
-
|
|
633
|
+
same scope-run. Because nothing is written, calling `gtd next --json` twice in a
|
|
634
|
+
row — a driver's own opening peek, a status poll, a curious human — derives
|
|
635
635
|
IDENTICAL `session.id`/`session.resume` values both times, since there is
|
|
636
636
|
nothing to poison: looking is free, and there is no separate claiming form to
|
|
637
637
|
protect. The per-scope survival story (a child machine's own excursion doesn't
|
|
@@ -792,7 +792,7 @@ invokes that script with.
|
|
|
792
792
|
carry one — there is no window to reopen after either, so their printed
|
|
793
793
|
artifact is the required half alone, with no trailing comment/subshell at all.
|
|
794
794
|
|
|
795
|
-
`gtd
|
|
795
|
+
`gtd next --json` carries one more field worth a custom driver's attention:
|
|
796
796
|
|
|
797
797
|
- **`log`** — the per-worktree loop log path, always present. It's derived from
|
|
798
798
|
the worktree's own git dir, so two worktrees looping concurrently never share
|
|
@@ -843,16 +843,16 @@ advance instead of settling.
|
|
|
843
843
|
|
|
844
844
|
### Drivers other than sh
|
|
845
845
|
|
|
846
|
-
The protocol above is JSON in (from `gtd
|
|
847
|
-
|
|
848
|
-
`gtd
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
846
|
+
The protocol above is JSON in (from `gtd next --json` alone), subprocesses out —
|
|
847
|
+
sh is one convenient shape, not the only one. A **program** parses
|
|
848
|
+
`gtd next --json`, switches on `kind`, and runs `gtd next`'s (plain-text) output
|
|
849
|
+
and `gtd land`'s (POSIX sh) output as subprocesses — no sh anywhere in it. A
|
|
850
|
+
**human** runs plain `gtd next` (there is no JSON form of it at all), does what
|
|
851
|
+
it says, and pastes `gtd land | sh`: plain-text output exists for exactly this,
|
|
852
|
+
printing the combined script ready to paste. An **agent** gets `gtd install` as
|
|
853
|
+
its instructions — the same protocol, in a form built to be pasted into a
|
|
854
|
+
context window rather than read. A **CI job** is the program case with the
|
|
855
|
+
`prompt` arm pointed at a headless agent CLI, and
|
|
856
856
|
`kind: "message"`/`kind: "stalled"` mapped onto "stop and report".
|
|
857
857
|
|
|
858
858
|
### A complete minimal driver
|
|
@@ -914,8 +914,9 @@ while :; do
|
|
|
914
914
|
# macOS, and POSIX guarantees only 4 KB, ARG_MAX), and a diff crosses
|
|
915
915
|
# that far sooner than you'd expect.
|
|
916
916
|
agent_turn() { printf '%s' "$gtd_content" | claude -p "$1" "$gtd_session_id" \
|
|
917
|
-
${gtd_model:+--model "$gtd_model"}
|
|
918
|
-
|
|
917
|
+
${gtd_model:+--model "$gtd_model"} \
|
|
918
|
+
${gtd_system:+--system-prompt "$gtd_system"} \
|
|
919
|
+
--dangerously-skip-permissions >>"$gtd_log" 2>&1; }
|
|
919
920
|
if [ "${gtd_session_resume:-}" = true ]
|
|
920
921
|
then agent_turn --resume || agent_turn --session-id
|
|
921
922
|
else agent_turn --session-id || agent_turn --resume
|
|
@@ -924,8 +925,16 @@ while :; do
|
|
|
924
925
|
while [ -n "${gtd_validate:-}" ] && ! fix="$(sh -c "$gtd_validate" 2>&1)"; do
|
|
925
926
|
n=$((n + 1)) && [ "$n" -gt 3 ] && { printf '%s\n' "$fix" >&2; exit 1; }
|
|
926
927
|
# $fix IS the fix prompt, verbatim — piped for the same reason as
|
|
927
|
-
# $gtd_content above
|
|
928
|
+
# $gtd_content above. Whether `claude --resume` re-applies the
|
|
929
|
+
# original session's model/system prompt is a harness detail gtd
|
|
930
|
+
# cannot verify from outside, so this passes the identical
|
|
931
|
+
# $gtd_model/$gtd_system on both calls rather than assume it does —
|
|
932
|
+
# otherwise this fix turn might silently fall back to Claude Code's
|
|
933
|
+
# own defaults while the turn that produced the file ran under the
|
|
934
|
+
# workflow's own model and persona.
|
|
928
935
|
printf '%s' "$fix" | claude -p --resume "$gtd_session_id" \
|
|
936
|
+
${gtd_model:+--model "$gtd_model"} \
|
|
937
|
+
${gtd_system:+--system-prompt "$gtd_system"} \
|
|
929
938
|
--dangerously-skip-permissions >>"$gtd_log" 2>&1
|
|
930
939
|
done ;;
|
|
931
940
|
esac
|
|
@@ -960,12 +969,13 @@ re-invocation authored and which therefore lands like any other decision (see
|
|
|
960
969
|
not gtd, decides, because "has the human read this gate" is run-scoped knowledge
|
|
961
970
|
gtd deliberately does not keep); `capture` lands a human's already-made edit
|
|
962
971
|
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
|
-
|
|
972
|
+
`prompt` sends it to the agent over stdin with
|
|
973
|
+
`$gtd_session_id`/`$gtd_model`/`$gtd_system` mapped onto the agent's session
|
|
974
|
+
flags — trying `resume`'s hinted flag first and falling back to the other on
|
|
975
|
+
failure, since the session id is derived, not remembered (see
|
|
976
|
+
[Driving the loop](#driving-the-loop) above) — and its own `$gtd_validate`
|
|
977
|
+
script's output re-prompted verbatim on failure (the driver owns only the retry
|
|
978
|
+
cap). Every optional variable (`$gtd_model`, `$gtd_system`, `$gtd_validate`,
|
|
969
979
|
`$gtd_session_resume`, `$gtd_idle`, `$gtd_settled`) is read as `${var:-}` or
|
|
970
980
|
`${var:+...}` — under `set -u`, the `--sh` document's own `unset` preamble makes
|
|
971
981
|
an absent field genuinely unset, not empty, so a bare `$gtd_model` would abort
|
|
@@ -979,10 +989,24 @@ the reference driver reads once more (a plain `gtd next`) only to DISPLAY that
|
|
|
979
989
|
gate's own message, the decision to stop already made from `$gtd_settled`/
|
|
980
990
|
`$gtd_idle` alone.
|
|
981
991
|
|
|
992
|
+
This paste passes `$gtd_system` on argv, and POSIX guarantees only 4 KB of argv
|
|
993
|
+
(`ARG_MAX`) — real systems are far higher (roughly 1 MB on both macOS and
|
|
994
|
+
Linux), and the bundled personas are only a few KB each, so this works
|
|
995
|
+
everywhere in practice. A driver shipping much larger system prompts, or
|
|
996
|
+
targeting a platform sitting at the POSIX floor, should write the string to a
|
|
997
|
+
file and pass that instead: gtd's own contract ends at emitting `gtd_system` as
|
|
998
|
+
a string, and how a driver hands that string to its agent CLI — argv, a temp
|
|
999
|
+
file, or something else — is the driver's own call, since it alone knows its
|
|
1000
|
+
platform's argv limit and whether it has a writable temp directory; gtd adds no
|
|
1001
|
+
flag, no file, and no mechanism of its own for this. (The doc-test below only
|
|
1002
|
+
proves this paste parses and runs against a `claude` shim — not that the flag is
|
|
1003
|
+
spelled or placed correctly; that's a `claude --help` check plus one live run,
|
|
1004
|
+
not something the green suite can catch.)
|
|
1005
|
+
|
|
982
1006
|
### The self-validation gate
|
|
983
1007
|
|
|
984
1008
|
After an agent turn at a state that declares `file:`+`mode:`, run the script:
|
|
985
|
-
either `gtd
|
|
1009
|
+
either `gtd next --json`'s own embedded `.validate` field (present at every
|
|
986
1010
|
`prompt` beat that hands over a validatable file), or, standalone,
|
|
987
1011
|
`gtd validate`'s own plain-text output — both resolve the exact same script from
|
|
988
1012
|
one shared resolver. Exit 0 means the file is well-formed — proceed to
|
|
@@ -1156,7 +1180,6 @@ workflow:
|
|
|
1156
1180
|
<name>:
|
|
1157
1181
|
format: <shell command> # both optional — {} is the format-only tier
|
|
1158
1182
|
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
1183
|
entry:
|
|
1161
1184
|
default: <machine name> # which machine is the ROOT instance
|
|
1162
1185
|
machines:
|
|
@@ -1181,8 +1204,8 @@ workflow:
|
|
|
1181
1204
|
retry:
|
|
1182
1205
|
max: <number>
|
|
1183
1206
|
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
|
|
1207
|
+
label: <string> # optional, opaque display name passed through `gtd next --json`
|
|
1208
|
+
file: <string> # optional, an Eta template naming the state's steering file RELATIVE to ".gtd/" — the compiler prepends that directory automatically
|
|
1186
1209
|
mode: <modeName> # optional, requires "file" — must be declared in `modes:` (qa/review are seeded for you; everything else, including prose, you declare)
|
|
1187
1210
|
reviewWindow: true # optional — open the review checkout window at rest here
|
|
1188
1211
|
reviewBase: true # optional — anchor the review window's diff base to this state's most-recent commit
|
|
@@ -1202,11 +1225,7 @@ derives a driver's session id).
|
|
|
1202
1225
|
The top-level `entry:` key (naming the root machine, `entry.default`) and a
|
|
1203
1226
|
state's own `entry: true` flag are the same word at two different levels, by
|
|
1204
1227
|
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.
|
|
1228
|
+
an extra manual entry point.
|
|
1210
1229
|
|
|
1211
1230
|
A workflow is authored as a TREE of reusable, parameterized machines — a
|
|
1212
1231
|
gate/loop written once and instantiated several times with different `with:`
|
|
@@ -1239,8 +1258,8 @@ Besides `it.vars` (below), a `script`/`prompt`/`message`/`commit` template sees:
|
|
|
1239
1258
|
|
|
1240
1259
|
A template never sees rendered diff CONTENT — no field carries a diff. It names
|
|
1241
1260
|
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
|
-
|
|
1261
|
+
render cheap (no diff computed on `gtd next`/`gtd lsp`) and the prompt small and
|
|
1262
|
+
cacheable.
|
|
1244
1263
|
|
|
1245
1264
|
Authoring or editing a workflow with a coding agent? `skills/authoring/SKILL.md`
|
|
1246
1265
|
is the agent-facing contract for producing a valid `workflow:` — the state
|
|
@@ -1401,10 +1420,10 @@ top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
|
|
|
1401
1420
|
`GTD_STYLEFORMATCONTRACT` environment variable):
|
|
1402
1421
|
|
|
1403
1422
|
- **`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
|
|
1423
|
+
generate content, not just three: the free-prose ones — the `.gtd/packages/`
|
|
1424
|
+
package files (`architecture.decompose`), `.gtd/SPEC_FEEDBACK.md`
|
|
1425
|
+
(`packages.item.spec.review`), and `.gtd/COMMIT_MSG.md` (`build.squashing`) —
|
|
1426
|
+
plus the four machine-parsed states named in the next bullet. Blanking
|
|
1408
1427
|
`GTD_STYLEBLOCK` strips the voice from all seven, including the machine-parsed
|
|
1409
1428
|
ones, not only the free-prose three. In short: why density matters before any
|
|
1410
1429
|
rule, answer-first with no preamble or restatement, blunt and imperative,
|
|
@@ -1417,17 +1436,17 @@ top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
|
|
|
1417
1436
|
ahead of the role sentence and well before any state-specific format-contract
|
|
1418
1437
|
text — `styleBlock` first, then `styleFormatContract`, at the four prompt
|
|
1419
1438
|
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 `
|
|
1439
|
+
(`.gtd/REQUIREMENTS.md` at `design.triage`, `.gtd/ARCHITECTURE.md` at
|
|
1440
|
+
`architecture.author`) and the `review`-mode one (`.gtd/REVIEW.md` at
|
|
1441
|
+
`build.review.reviewing`), plus `.gtd/REQUIREMENTS.md` again at
|
|
1423
1442
|
`build.review.collecting`, which classifies a review round straight into it.
|
|
1424
1443
|
|
|
1425
1444
|
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).
|
|
1445
|
+
agent — writes them: `.gtd/FEEDBACK.md` (verbatim test-suite output plus a HEAD
|
|
1446
|
+
stamp — the tool's content, not gtd's prose), `.gtd/NEXT.md` (a bare path, no
|
|
1447
|
+
prose to style), and `.gtd/REVIEW_RAW.md` (gtd's own prose, hand-tightened in
|
|
1448
|
+
the voice directly in `build.review.deciding`'s script rather than templated in
|
|
1449
|
+
through either variable).
|
|
1431
1450
|
|
|
1432
1451
|
### Lookup and precedence
|
|
1433
1452
|
|
|
@@ -1502,8 +1521,8 @@ option"/"uncheck this option" code actions on each option — offered anywhere o
|
|
|
1502
1521
|
the option's list item, including any wrapped continuation lines, not just its
|
|
1503
1522
|
own `- [ ]` line — diagnostics for both (live as you edit), and a
|
|
1504
1523
|
`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
|
|
1524
|
+
including `idle`, whose `.gtd/TODO.md` hint gives the one keybinding an answer
|
|
1525
|
+
even before a process has started. The command only names that path — it never
|
|
1507
1526
|
stat-checks or creates it — so on a repo that has never run gtd, `.gtd/` may not
|
|
1508
1527
|
exist yet and editors differ on opening a file whose parent directory is missing
|
|
1509
1528
|
(an empty buffer that creates it on save vs. refusing the path outright); this
|