@pmelab/gtd 9.3.0 → 9.5.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 +140 -42
- package/dist/gtd.bundle.mjs +266 -36
- package/package.json +1 -1
- package/schema.json +9 -1
package/README.md
CHANGED
|
@@ -150,7 +150,11 @@ questions: each open question offers a couple of candidate answers plus a
|
|
|
150
150
|
`- [ ] _your answer_` slot, and you tick exactly one per question (the gate
|
|
151
151
|
won't let the phase advance while any question is unanswered) — but a phase
|
|
152
152
|
whose document has no open questions skips that human stop entirely and falls
|
|
153
|
-
straight through.
|
|
153
|
+
straight through. If a question's options ever come out as prose instead of
|
|
154
|
+
`- [ ]` rows, there is no checkbox for the gate to see, so it stays permanently
|
|
155
|
+
unanswered; un-wedge it yourself: hand-write the `- [ ]` rows and tick one,
|
|
156
|
+
delete that question, or delete the whole `## Open Questions` section to accept
|
|
157
|
+
the plan as-is.
|
|
154
158
|
|
|
155
159
|
Once the product questions are settled, `architecture.author` picks up as a
|
|
156
160
|
**cold reader** — a separate machine with its own memory scope, so it does not
|
|
@@ -185,30 +189,41 @@ alone is not a pending change, and only actually removing it from disk counts as
|
|
|
185
189
|
a deletion). The next landing's own script closes the window before it commits.
|
|
186
190
|
Tick a box as you review each hunk (ticking just records "I read this"), and
|
|
187
191
|
leave a **comment** to request changes: a note on a line, an inline
|
|
188
|
-
`// TODO`-style comment in the code, or a direct code edit.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
review
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
`// TODO`-style comment in the code, or a direct code edit. A comment sends a
|
|
193
|
+
FULL development lap, not a quick fix-and-re-review: an agent first judges
|
|
194
|
+
whether your comment is actually actionable (a genuinely approving remark with
|
|
195
|
+
no code edit short-circuits straight to sign-off instead), and an actionable
|
|
196
|
+
round is re-planned from scratch through triage, architecture, and the package
|
|
197
|
+
queue again — a hand-edit you made during review is treated as a **sketch**, the
|
|
198
|
+
same as any other change that starts a process, not a fix the agent builds on:
|
|
199
|
+
it is reverted out of the tree first, and your intent survives only in your own
|
|
200
|
+
review-round commit for triage to read. There is no baseline check on the way
|
|
201
|
+
back into planning. If a styled `.gtd/REVIEW.md` ever comes out malformed (a
|
|
202
|
+
paragraph where a `- [ ] ./path#line` row belongs), `gtd check review` refuses
|
|
203
|
+
the step before it commits: the file stays exactly as written in the working
|
|
204
|
+
tree, unlanded, and re-running the same prompt is the recovery — nothing is
|
|
205
|
+
lost. Only the turn that drafts the final squash message resumes the session
|
|
206
|
+
that built the feature in the first place (the review tail is nested inside that
|
|
207
|
+
build identity rather than sitting beside it) — an actionable round leaves that
|
|
208
|
+
identity entirely, so it starts a fresh session like any other process. Ticking
|
|
209
|
+
every box with no comment is the sign-off, which collapses the whole process
|
|
210
|
+
into one commit (a **squash finale** whose message an agent drafts). Landing
|
|
211
|
+
with a box still unticked and no comment is refused (finish reviewing first), as
|
|
212
|
+
is deleting `.gtd/REVIEW.md`. Both refusals hold wherever the review doc lives:
|
|
213
|
+
repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md` at the repo root)
|
|
214
|
+
changes nothing about them — your own edit to the review doc is never mistaken
|
|
215
|
+
for a code comment, and the doc's pre-turn copy is read at the review window's
|
|
216
|
+
saved head rather than at the rewound `HEAD`.
|
|
205
217
|
|
|
206
218
|
A second entry, the same review tail's own direct entry point —
|
|
207
219
|
`gtd --entry review-gate.check --var reviewBase=<commitish>` starts a brand new
|
|
208
|
-
process reviewing `<commitish>..HEAD` with no build of its own
|
|
209
|
-
colleague's PR branch (`review-gate.check`'s `reviewBase:` is a
|
|
210
|
-
to the `reviewBase` var, so supplying it via `--var` fixes the
|
|
211
|
-
diff base to that commitish)
|
|
220
|
+
process reviewing `<commitish>..HEAD` with no build of its own on a clean
|
|
221
|
+
sign-off, e.g. a colleague's PR branch (`review-gate.check`'s `reviewBase:` is a
|
|
222
|
+
template bound to the `reviewBase` var, so supplying it via `--var` fixes the
|
|
223
|
+
whole process's diff base to that commitish) — though an actionable round on
|
|
224
|
+
this entry runs the same full triage → gates → architecture → package-queue lap
|
|
225
|
+
as any other, same as `re-unwind` re-plans a build process's own review
|
|
226
|
+
feedback. A clean sign-off's squash keeps and describes only the fixes made
|
|
212
227
|
_during_ the review (not the reviewed changeset); a clean sign-off with no fixes
|
|
213
228
|
becomes an empty `chore: human review` commit. A third entry,
|
|
214
229
|
`gtd --entry fix-precheck`, starts from a clean `idle` and goes straight into
|
|
@@ -240,7 +255,18 @@ per-file var gtd never writes and never reads, since it names your own sketch
|
|
|
240
255
|
pad, not a file any state produces. A separate `stateDir` var (default `.gtd`)
|
|
241
256
|
names only where the check scripts keep their own scratch/bookkeeping,
|
|
242
257
|
independent of the per-file vars — relocate one steering file without touching
|
|
243
|
-
it.
|
|
258
|
+
it. The workflow declares its plumbing directory once, at the top level of the
|
|
259
|
+
`workflow:` value (`stateDir: <%= it.vars.stateDir %>` in the bundled template),
|
|
260
|
+
rendered from that same `stateDir` var — this is what the engine itself reads to
|
|
261
|
+
tell gtd's own bookkeeping apart from your code (e.g. the review window's revert
|
|
262
|
+
pathspec, the step guards' code-vs-plumbing check), not just a value the
|
|
263
|
+
templates happen to share. The rendered value is constrained: it must name a
|
|
264
|
+
directory inside the repository — not the repo root, not an absolute path, and
|
|
265
|
+
not a path that escapes the repository via `..` — and it must be spelled
|
|
266
|
+
canonically: no `.` and no empty path segments (`a/./state` or `a//state` are
|
|
267
|
+
rejected, not rewritten), though a leading `./` and a trailing `/` are accepted
|
|
268
|
+
— or the next `gtd next`/`gtd status`/`gtd land` fails loudly with that message,
|
|
269
|
+
rather than silently excluding the whole tree from the review window's revert.
|
|
244
270
|
|
|
245
271
|
To inspect or change the machine itself, see [Configuration](#configuration) —
|
|
246
272
|
the workflow is just `.gtdrc` config.
|
|
@@ -460,11 +486,15 @@ started FROM. Entering a **descendant** scope (e.g. dipping from `build` into
|
|
|
460
486
|
a nested child machine, then back to the parent, still resumes the SAME parent
|
|
461
487
|
conversation; entering a **sibling or unrelated** scope does start a fresh one.
|
|
462
488
|
The bundled template's `build.review` (the human review tail) is a worked
|
|
463
|
-
example: it is nested INSIDE `build` (the builder's own machine)
|
|
464
|
-
|
|
465
|
-
`build.squashing`
|
|
466
|
-
|
|
467
|
-
|
|
489
|
+
example: it is nested INSIDE `build` (the builder's own machine) so that a
|
|
490
|
+
`gtd --entry fix-precheck` run — `build.fix` -> `build.health.check` ->
|
|
491
|
+
`build.review.*` -> `build.squashing` — stays inside one subtree, letting
|
|
492
|
+
`build.squashing` resume the SAME session that made the fixes instead of a
|
|
493
|
+
root-level sibling forcing it to re-derive the range from scratch on every pass
|
|
494
|
+
through the tail. (An actionable review round breaks the run on purpose instead
|
|
495
|
+
— it leaves `build` entirely through a root-level `re-unwind` state and a full
|
|
496
|
+
re-plan, since a hand-edit made during review is a sketch to reconsider, not a
|
|
497
|
+
fix to build on.) Two instances of the same reusable machine (e.g.
|
|
468
498
|
`build.health` and `packages.item.health`, both instantiating `healthGate`) get
|
|
469
499
|
different scopes and so never share a key, even though they're the "same shaped"
|
|
470
500
|
machine. One consequence is a structural guarantee: **a reviewer's turn never
|
|
@@ -830,18 +860,19 @@ its own retry/resume logic beyond "if the script failed, ask gtd again."
|
|
|
830
860
|
A mode's `format:` command may reformat a steering file — whitespace, wrapping,
|
|
831
861
|
reordering — but must NEVER change what a land-capture guard would decide. gtd's
|
|
832
862
|
guards (the review sign-off check, the feedback-progress check, the
|
|
833
|
-
answer-completeness check — `src/StepGuards.ts`)
|
|
834
|
-
bytes are on disk at the moment `gtd land` runs,
|
|
835
|
-
emitted script's own `format:` line has run (the
|
|
836
|
-
`validate:` then the commit — see
|
|
837
|
-
`renderSteeringCommands` — but gtd's decision and the
|
|
838
|
-
are different processes at different times, so there's
|
|
839
|
-
between "gtd decided" and "the script formatted"). That's
|
|
840
|
-
every built-in guard judges content, not incidental formatting
|
|
841
|
-
normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in
|
|
842
|
-
`format:` command, the same rule binds it: a formatter that also
|
|
843
|
-
— ticking a box, stripping a paragraph — makes the guard's
|
|
844
|
-
file's actual content disagree, and gtd will not catch that for
|
|
863
|
+
answer-completeness check, the require-revert check — `src/StepGuards.ts`)
|
|
864
|
+
decide ONCE, against whichever bytes are on disk at the moment `gtd land` runs,
|
|
865
|
+
which may be before OR after an emitted script's own `format:` line has run (the
|
|
866
|
+
script runs `format:` then `validate:` then the commit — see
|
|
867
|
+
`src/SteeringMode.ts`'s `renderSteeringCommands` — but gtd's decision and the
|
|
868
|
+
driver's script execution are different processes at different times, so there's
|
|
869
|
+
no guaranteed ordering between "gtd decided" and "the script formatted"). That's
|
|
870
|
+
only safe because every built-in guard judges content, not incidental formatting
|
|
871
|
+
(e.g. it normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in
|
|
872
|
+
your own `format:` command, the same rule binds it: a formatter that also
|
|
873
|
+
changes meaning — ticking a box, stripping a paragraph — makes the guard's
|
|
874
|
+
decision and the file's actual content disagree, and gtd will not catch that for
|
|
875
|
+
you.
|
|
845
876
|
|
|
846
877
|
One case never runs your `format:` (or `validate:`) at all: a step whose diff
|
|
847
878
|
DELETES the state's own `file:`. Deleting it is a legitimate outcome — a review
|
|
@@ -928,6 +959,7 @@ workflow:
|
|
|
928
959
|
<name>:
|
|
929
960
|
format: <shell command> # both optional — {} is the format-only tier
|
|
930
961
|
validate: <shell command>
|
|
962
|
+
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
|
|
931
963
|
entry:
|
|
932
964
|
default: <machine name> # which machine is the ROOT instance
|
|
933
965
|
machines:
|
|
@@ -960,6 +992,7 @@ workflow:
|
|
|
960
992
|
# reviewBase: <Eta template> # OR a template — rendered (only meaningful entering via --entry) to a commitish that fixes the WHOLE PROCESS's diff base
|
|
961
993
|
requireProgress: true # optional, requires "file" — refuse a turn whose only change deletes this state's own `file:`
|
|
962
994
|
answerGate: true # optional, requires "file" — refuse a turn until every open question in the (qa-mode) `file:` is answered
|
|
995
|
+
requireRevert: true # optional, requires "file" — refuse a turn until the human's review-round paths actually match the review base's parent
|
|
963
996
|
entry: true # optional — an EXTRA reachability root (`entries.manual`), enterable via `gtd --entry <this state's qualified name>` — NOT a precondition for `--entry` (any declared, non-commit state is a valid target)
|
|
964
997
|
<local>: { machine: <name>, with: { <param>: <value> } } # a REFERENCE — instantiates <name> as a child, qualified as `<local>.<childLocal>`
|
|
965
998
|
```
|
|
@@ -972,7 +1005,11 @@ derives a driver's session id).
|
|
|
972
1005
|
The top-level `entry:` key (naming the root machine, `entry.default`) and a
|
|
973
1006
|
state's own `entry: true` flag are the same word at two different levels, by
|
|
974
1007
|
design: one selects the workflow's root machine, the other opts one state in as
|
|
975
|
-
an extra manual entry point.
|
|
1008
|
+
an extra manual entry point. The top-level `stateDir:` key and the
|
|
1009
|
+
`vars.stateDir` var it renders from are the same call: the definition-level
|
|
1010
|
+
declaration is what the engine reads (e.g. to tell gtd's own plumbing apart from
|
|
1011
|
+
your code), while the var is the knob you actually override — repointing
|
|
1012
|
+
`vars.stateDir` moves both.
|
|
976
1013
|
|
|
977
1014
|
A workflow is authored as a TREE of reusable, parameterized machines — a
|
|
978
1015
|
gate/loop written once and instantiated several times with different `with:`
|
|
@@ -992,7 +1029,12 @@ Besides `it.vars` (below), a `script`/`prompt`/`message`/`commit` template sees:
|
|
|
992
1029
|
- **`it.startCommit`** — the process's diff base (the commit the current process
|
|
993
1030
|
started from, or the base a `--var reviewBase=<commitish>` entry resolved to).
|
|
994
1031
|
- **`it.reviewBase`** — the previous review round's boundary, falling back to
|
|
995
|
-
`it.startCommit` on a first review.
|
|
1032
|
+
`it.startCommit` on a first review. In the bundled template, an actionable
|
|
1033
|
+
round's NEXT review therefore covers the revert of the human's own lines
|
|
1034
|
+
(`re-unwind`) followed by the whole lap that re-derives and re-implements them
|
|
1035
|
+
— the net diff is the final implementation, the right thing to review, but no
|
|
1036
|
+
longer the tiny "just the fixes" delta a quick fix-and-re-review would have
|
|
1037
|
+
shown.
|
|
996
1038
|
- **`it.retainedBase`** — the process's trace/retry boundary, what a squash
|
|
997
1039
|
actually keeps (never moved by a review entry's fixed base).
|
|
998
1040
|
- **`it.currentCommit`** / **`it.previousCommit`** — HEAD's hash and its parent,
|
|
@@ -1095,6 +1137,16 @@ model, pattern grammar, load-time rules, and how to verify a change compiles.
|
|
|
1095
1137
|
> `gtd abandon` it (or finish it on the pre-upgrade workflow version) before
|
|
1096
1138
|
> upgrading.
|
|
1097
1139
|
|
|
1140
|
+
> **Upgrading a `workflow:` that still references `build.addressing`?** That
|
|
1141
|
+
> state is REMOVED, not renamed — the implementer's own follow-through on review
|
|
1142
|
+
> feedback is gone outright, since an actionable review round is now re-planned
|
|
1143
|
+
> from scratch through a new root-level `re-unwind` state (reverting the human's
|
|
1144
|
+
> hand-edit) instead of being built upon. A non-actionable round (an approving
|
|
1145
|
+
> remark with no code edit) short-circuits straight to `build.squashing` instead
|
|
1146
|
+
> of spending a lap on nothing. As with every rename above, an in-flight process
|
|
1147
|
+
> resting at `build.addressing` can no longer be resumed after upgrading;
|
|
1148
|
+
> `gtd abandon` it (or finish it on the pre-upgrade workflow version) first.
|
|
1149
|
+
|
|
1098
1150
|
### Variables
|
|
1099
1151
|
|
|
1100
1152
|
Every template — `script`/`prompt`/`message`/`commit`, a machine's own `model:`,
|
|
@@ -1134,6 +1186,52 @@ vars:
|
|
|
1134
1186
|
GTD_TESTCOMMAND="npm run test -- --bail" gtd next
|
|
1135
1187
|
```
|
|
1136
1188
|
|
|
1189
|
+
#### The voice
|
|
1190
|
+
|
|
1191
|
+
gtd ships its own writing voice for the files it generates — the default, not an
|
|
1192
|
+
opt-in. It is a specialisation of the "Spartan" output style from
|
|
1193
|
+
[alexgreensh/attention-span](https://github.com/alexgreensh/attention-span)
|
|
1194
|
+
(AGPL-3.0), written from a reading of that project's version `0.6`: gtd's own
|
|
1195
|
+
prose stating the same density discipline, rewritten for deliverables (files
|
|
1196
|
+
that run as long as the work needs) rather than chat replies. No upstream text
|
|
1197
|
+
ships in gtd's bundle. This is a point-in-time derivation with no refresh
|
|
1198
|
+
mechanism — it will silently go stale as upstream moves on, and nothing in gtd
|
|
1199
|
+
will notice.
|
|
1200
|
+
|
|
1201
|
+
It is two independently-overridable variables, each an ordinary `vars:` entry
|
|
1202
|
+
that can be overridden or blanked through the same layers as any other (a
|
|
1203
|
+
top-level `.gtdrc` `vars:` key, or the matching `GTD_STYLEBLOCK` /
|
|
1204
|
+
`GTD_STYLEFORMATCONTRACT` environment variable):
|
|
1205
|
+
|
|
1206
|
+
- **`styleBlock`** — the voice itself, injected at all seven prompt states that
|
|
1207
|
+
generate content, not just three: the free-prose ones — the `packagesDir`
|
|
1208
|
+
package files (`architecture.decompose`), `specFeedbackFile`
|
|
1209
|
+
(`packages.item.spec.review`), and `commitMsgFile` (`build.squashing`) — plus
|
|
1210
|
+
the four machine-parsed states named in the next bullet. Blanking
|
|
1211
|
+
`GTD_STYLEBLOCK` strips the voice from all seven, including the machine-parsed
|
|
1212
|
+
ones, not only the free-prose three. In short: why density matters before any
|
|
1213
|
+
rule, answer-first with no preamble or restatement, blunt and imperative,
|
|
1214
|
+
plain words, bold carries the load, ship the artifact bare, compressing is not
|
|
1215
|
+
dropping, one idea per block, flag risk in one blunt line, never narrate the
|
|
1216
|
+
work — and never-trim outranks every other rule in the set.
|
|
1217
|
+
- **`styleFormatContract`** — the structural override for machine-parsed files:
|
|
1218
|
+
the format contract (headings, checkbox rows, marker lines) outranks the
|
|
1219
|
+
voice, and a violation refuses the turn. It renders at the top of the prompt,
|
|
1220
|
+
ahead of the role sentence and well before any state-specific format-contract
|
|
1221
|
+
text — `styleBlock` first, then `styleFormatContract`, at the four prompt
|
|
1222
|
+
states whose output a parser reads: the two `qa`-mode steering files
|
|
1223
|
+
(`requirementsFile` at `design.triage`, `architectureFile` at
|
|
1224
|
+
`architecture.author`) and the `review`-mode one (`reviewFile` at
|
|
1225
|
+
`build.review.reviewing`), plus `requirementsFile` again at
|
|
1226
|
+
`build.review.collecting`, which classifies a review round straight into it.
|
|
1227
|
+
|
|
1228
|
+
Three more generated files carry no injected voice, because a script — not an
|
|
1229
|
+
agent — writes them: `feedbackFile` (verbatim test-suite output plus a HEAD
|
|
1230
|
+
stamp — the tool's content, not gtd's prose), `nextFile` (a bare path, no prose
|
|
1231
|
+
to style), and `reviewRawFile` (gtd's own prose, hand-tightened in the voice
|
|
1232
|
+
directly in `build.review.deciding`'s script rather than templated in through
|
|
1233
|
+
either variable).
|
|
1234
|
+
|
|
1137
1235
|
### Lookup and precedence
|
|
1138
1236
|
|
|
1139
1237
|
gtd walks from the current working directory **up to your home directory** (or
|