@pmelab/gtd 9.2.0 → 9.4.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
@@ -121,10 +121,14 @@ reads intent first, glob second.
121
121
  to the tree — a hand-edit to real code, a scratch note in some file, anything at
122
122
  all — as a sketch to be finished, never as work to be preserved: there is no
123
123
  fork on which steering file you happen to create, and `idle` has exactly one
124
- outgoing edge, into `unwind`. `unwind` reverts that whole diff back out of your
125
- working tree (`git revert --no-commit` against the commit it just landed in)
126
- before planning ever starts — your tree is back to exactly what it was, and your
127
- intent doesn't disappear, it survives in history for `design.triage` to read.
124
+ outgoing edge, into `unwind`. `.gtd/TODO.md` (the `todoFile` var) is a good
125
+ default place to start sketching when you'd rather write a note than touch code
126
+ — despite living beside the workflow's own state files, that sketch is your
127
+ input for `design.triage` to fold in, never gtd bookkeeping to preserve or
128
+ ignore. `unwind` reverts that whole diff back out of your working tree
129
+ (`git revert --no-commit` against the commit it just landed in) before planning
130
+ ever starts — your tree is back to exactly what it was, and your intent doesn't
131
+ disappear, it survives in history for `design.triage` to read.
128
132
 
129
133
  From there, `start-gate.check` runs your test suite on the tree as it now stands
130
134
  — which, thanks to the unwind, is simply your repo's own baseline. The rule is
@@ -181,30 +185,37 @@ alone is not a pending change, and only actually removing it from disk counts as
181
185
  a deletion). The next landing's own script closes the window before it commits.
182
186
  Tick a box as you review each hunk (ticking just records "I read this"), and
183
187
  leave a **comment** to request changes: a note on a line, an inline
184
- `// TODO`-style comment in the code, or a direct code edit. Any comment sends a
185
- build + re-review round — an agent first turns your comments into an explicit
186
- instruction list, then a build turn implements it (a re-review then covers only
187
- the follow-through, and a hand-edit is treated as your own fix the agent
188
- completes without reverting your lines; a comment can't be silently dropped — a
189
- build turn that addresses nothing is refused). The build turn that follows
190
- through on feedback and the turn that drafts the final squash message both
191
- resume the same session that built the feature in the first place, since the
192
- review tail is nested inside that build identity rather than sitting beside it.
193
- Ticking every box with no comment is the sign-off, which collapses the whole
194
- process into one commit (a **squash finale** whose message an agent drafts).
195
- Landing with a box still unticked and no comment is refused (finish reviewing
196
- first), as is deleting `.gtd/REVIEW.md`. Both refusals hold wherever the review
197
- doc lives: repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md` at the
198
- repo root) changes nothing about them — your own edit to the review doc is never
199
- mistaken for a code comment, and the doc's pre-turn copy is read at the review
200
- window's saved head rather than at the rewound `HEAD`.
188
+ `// TODO`-style comment in the code, or a direct code edit. A comment sends a
189
+ FULL development lap, not a quick fix-and-re-review: an agent first judges
190
+ whether your comment is actually actionable (a genuinely approving remark with
191
+ no code edit short-circuits straight to sign-off instead), and an actionable
192
+ round is re-planned from scratch through triage, architecture, and the package
193
+ queue again — a hand-edit you made during review is treated as a **sketch**, the
194
+ same as any other change that starts a process, not a fix the agent builds on:
195
+ it is reverted out of the tree first, and your intent survives only in your own
196
+ review-round commit for triage to read. There is no baseline check on the way
197
+ back into planning. Only the turn that drafts the final squash message resumes
198
+ the session that built the feature in the first place (the review tail is nested
199
+ inside that build identity rather than sitting beside it) — an actionable round
200
+ leaves that identity entirely, so it starts a fresh session like any other
201
+ process. Ticking every box with no comment is the sign-off, which collapses the
202
+ whole process into one commit (a **squash finale** whose message an agent
203
+ drafts). Landing with a box still unticked and no comment is refused (finish
204
+ reviewing first), as is deleting `.gtd/REVIEW.md`. Both refusals hold wherever
205
+ the review doc lives: repointing `reviewFile` out of `.gtd/` (say to `REVIEW.md`
206
+ at the repo root) changes nothing about them — your own edit to the review doc
207
+ is never mistaken for a code comment, and the doc's pre-turn copy is read at the
208
+ review window's saved head rather than at the rewound `HEAD`.
201
209
 
202
210
  A second entry, the same review tail's own direct entry point —
203
211
  `gtd --entry review-gate.check --var reviewBase=<commitish>` starts a brand new
204
- process reviewing `<commitish>..HEAD` with no build of its own, e.g. a
205
- colleague's PR branch (`review-gate.check`'s `reviewBase:` is a template bound
206
- to the `reviewBase` var, so supplying it via `--var` fixes the whole process's
207
- diff base to that commitish). Its squash keeps and describes only the fixes made
212
+ process reviewing `<commitish>..HEAD` with no build of its own on a clean
213
+ sign-off, e.g. a colleague's PR branch (`review-gate.check`'s `reviewBase:` is a
214
+ template bound to the `reviewBase` var, so supplying it via `--var` fixes the
215
+ whole process's diff base to that commitish) — though an actionable round on
216
+ this entry runs the same full triage → gates → architecture → package-queue lap
217
+ as any other, same as `re-unwind` re-plans a build process's own review
218
+ feedback. A clean sign-off's squash keeps and describes only the fixes made
208
219
  _during_ the review (not the reviewed changeset); a clean sign-off with no fixes
209
220
  becomes an empty `chore: human review` commit. A third entry,
210
221
  `gtd --entry fix-precheck`, starts from a clean `idle` and goes straight into
@@ -227,13 +238,27 @@ to target a state.
227
238
  Every agent state routes its model through two `vars` tiers — `plannerModel`
228
239
  (heavier planning and review) and `coderModel` (the coding turns) — so you can
229
240
  repoint the models globally in one place (a `vars:` edit or a `GTD_PLANNERMODEL`
230
- override) instead of per state. Steering-file path vars (`feedbackFile`,
231
- `reviewFile`, …) work the same way, and propagate to the `on` patterns that
232
- route on them too — a repointed path var actually reroutes the machine, not just
233
- the templates that read/write the file. A separate `stateDir` var (default
234
- `.gtd`) names only where the check scripts keep their own scratch/bookkeeping,
241
+ override) instead of per state. Steering-file path vars (`todoFile`,
242
+ `feedbackFile`, `reviewFile`, …) work the same way, and propagate to the `on`
243
+ patterns that route on them too — a repointed path var actually reroutes the
244
+ machine, not just the templates that read/write the file. `todoFile` (default
245
+ `.gtd/TODO.md`, `idle`'s own `file:` hint) is the one exception: it's the only
246
+ per-file var gtd never writes and never reads, since it names your own sketch
247
+ pad, not a file any state produces. A separate `stateDir` var (default `.gtd`)
248
+ names only where the check scripts keep their own scratch/bookkeeping,
235
249
  independent of the per-file vars — relocate one steering file without touching
236
- it.
250
+ it. The workflow declares its plumbing directory once, at the top level of the
251
+ `workflow:` value (`stateDir: <%= it.vars.stateDir %>` in the bundled template),
252
+ rendered from that same `stateDir` var — this is what the engine itself reads to
253
+ tell gtd's own bookkeeping apart from your code (e.g. the review window's revert
254
+ pathspec, the step guards' code-vs-plumbing check), not just a value the
255
+ templates happen to share. The rendered value is constrained: it must name a
256
+ directory inside the repository — not the repo root, not an absolute path, and
257
+ not a path that escapes the repository via `..` — and it must be spelled
258
+ canonically: no `.` and no empty path segments (`a/./state` or `a//state` are
259
+ rejected, not rewritten), though a leading `./` and a trailing `/` are accepted
260
+ — or the next `gtd next`/`gtd status`/`gtd land` fails loudly with that message,
261
+ rather than silently excluding the whole tree from the review window's revert.
237
262
 
238
263
  To inspect or change the machine itself, see [Configuration](#configuration) —
239
264
  the workflow is just `.gtdrc` config.
@@ -453,11 +478,15 @@ started FROM. Entering a **descendant** scope (e.g. dipping from `build` into
453
478
  a nested child machine, then back to the parent, still resumes the SAME parent
454
479
  conversation; entering a **sibling or unrelated** scope does start a fresh one.
455
480
  The bundled template's `build.review` (the human review tail) is a worked
456
- example: it is nested INSIDE `build` (the builder's own machine) precisely
457
- because that descendant relationship is what lets `build.addressing` and
458
- `build.squashing` resume the session that built the feature across a full review
459
- round-trip, instead of a root-level sibling breaking that run on every pass
460
- through the tail. Two instances of the same reusable machine (e.g.
481
+ example: it is nested INSIDE `build` (the builder's own machine) so that a
482
+ `gtd --entry fix-precheck` run — `build.fix` -> `build.health.check` ->
483
+ `build.review.*` -> `build.squashing` — stays inside one subtree, letting
484
+ `build.squashing` resume the SAME session that made the fixes instead of a
485
+ root-level sibling forcing it to re-derive the range from scratch on every pass
486
+ through the tail. (An actionable review round breaks the run on purpose instead
487
+ — it leaves `build` entirely through a root-level `re-unwind` state and a full
488
+ re-plan, since a hand-edit made during review is a sketch to reconsider, not a
489
+ fix to build on.) Two instances of the same reusable machine (e.g.
461
490
  `build.health` and `packages.item.health`, both instantiating `healthGate`) get
462
491
  different scopes and so never share a key, even though they're the "same shaped"
463
492
  machine. One consequence is a structural guarantee: **a reviewer's turn never
@@ -823,18 +852,19 @@ its own retry/resume logic beyond "if the script failed, ask gtd again."
823
852
  A mode's `format:` command may reformat a steering file — whitespace, wrapping,
824
853
  reordering — but must NEVER change what a land-capture guard would decide. gtd's
825
854
  guards (the review sign-off check, the feedback-progress check, the
826
- answer-completeness check — `src/StepGuards.ts`) decide ONCE, against whichever
827
- bytes are on disk at the moment `gtd land` runs, which may be before OR after an
828
- emitted script's own `format:` line has run (the script runs `format:` then
829
- `validate:` then the commit — see `src/SteeringMode.ts`'s
830
- `renderSteeringCommands` — but gtd's decision and the driver's script execution
831
- are different processes at different times, so there's no guaranteed ordering
832
- between "gtd decided" and "the script formatted"). That's only safe because
833
- every built-in guard judges content, not incidental formatting (e.g. it
834
- normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in your own
835
- `format:` command, the same rule binds it: a formatter that also changes meaning
836
- — ticking a box, stripping a paragraph — makes the guard's decision and the
837
- file's actual content disagree, and gtd will not catch that for you.
855
+ answer-completeness check, the require-revert check — `src/StepGuards.ts`)
856
+ decide ONCE, against whichever bytes are on disk at the moment `gtd land` runs,
857
+ which may be before OR after an emitted script's own `format:` line has run (the
858
+ script runs `format:` then `validate:` then the commit — see
859
+ `src/SteeringMode.ts`'s `renderSteeringCommands` — but gtd's decision and the
860
+ driver's script execution are different processes at different times, so there's
861
+ no guaranteed ordering between "gtd decided" and "the script formatted"). That's
862
+ only safe because every built-in guard judges content, not incidental formatting
863
+ (e.g. it normalizes `[ ]`/`[x]` checkboxes before comparing). If you plug in
864
+ your own `format:` command, the same rule binds it: a formatter that also
865
+ changes meaning — ticking a box, stripping a paragraph — makes the guard's
866
+ decision and the file's actual content disagree, and gtd will not catch that for
867
+ you.
838
868
 
839
869
  One case never runs your `format:` (or `validate:`) at all: a step whose diff
840
870
  DELETES the state's own `file:`. Deleting it is a legitimate outcome — a review
@@ -921,6 +951,7 @@ workflow:
921
951
  <name>:
922
952
  format: <shell command> # both optional — {} is the format-only tier
923
953
  validate: <shell command>
954
+ 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
924
955
  entry:
925
956
  default: <machine name> # which machine is the ROOT instance
926
957
  machines:
@@ -953,6 +984,7 @@ workflow:
953
984
  # reviewBase: <Eta template> # OR a template — rendered (only meaningful entering via --entry) to a commitish that fixes the WHOLE PROCESS's diff base
954
985
  requireProgress: true # optional, requires "file" — refuse a turn whose only change deletes this state's own `file:`
955
986
  answerGate: true # optional, requires "file" — refuse a turn until every open question in the (qa-mode) `file:` is answered
987
+ requireRevert: true # optional, requires "file" — refuse a turn until the human's review-round paths actually match the review base's parent
956
988
  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)
957
989
  <local>: { machine: <name>, with: { <param>: <value> } } # a REFERENCE — instantiates <name> as a child, qualified as `<local>.<childLocal>`
958
990
  ```
@@ -965,7 +997,11 @@ derives a driver's session id).
965
997
  The top-level `entry:` key (naming the root machine, `entry.default`) and a
966
998
  state's own `entry: true` flag are the same word at two different levels, by
967
999
  design: one selects the workflow's root machine, the other opts one state in as
968
- an extra manual entry point.
1000
+ an extra manual entry point. The top-level `stateDir:` key and the
1001
+ `vars.stateDir` var it renders from are the same call: the definition-level
1002
+ declaration is what the engine reads (e.g. to tell gtd's own plumbing apart from
1003
+ your code), while the var is the knob you actually override — repointing
1004
+ `vars.stateDir` moves both.
969
1005
 
970
1006
  A workflow is authored as a TREE of reusable, parameterized machines — a
971
1007
  gate/loop written once and instantiated several times with different `with:`
@@ -985,7 +1021,12 @@ Besides `it.vars` (below), a `script`/`prompt`/`message`/`commit` template sees:
985
1021
  - **`it.startCommit`** — the process's diff base (the commit the current process
986
1022
  started from, or the base a `--var reviewBase=<commitish>` entry resolved to).
987
1023
  - **`it.reviewBase`** — the previous review round's boundary, falling back to
988
- `it.startCommit` on a first review.
1024
+ `it.startCommit` on a first review. In the bundled template, an actionable
1025
+ round's NEXT review therefore covers the revert of the human's own lines
1026
+ (`re-unwind`) followed by the whole lap that re-derives and re-implements them
1027
+ — the net diff is the final implementation, the right thing to review, but no
1028
+ longer the tiny "just the fixes" delta a quick fix-and-re-review would have
1029
+ shown.
989
1030
  - **`it.retainedBase`** — the process's trace/retry boundary, what a squash
990
1031
  actually keeps (never moved by a review entry's fixed base).
991
1032
  - **`it.currentCommit`** / **`it.previousCommit`** — HEAD's hash and its parent,
@@ -1080,11 +1121,23 @@ model, pattern grammar, load-time rules, and how to verify a change compiles.
1080
1121
  > `design.gate.answer`, `design.technical-author` → `architecture.author`,
1081
1122
  > `design.technical-answer` → `architecture.gate.answer`, `design.decompose` →
1082
1123
  > `architecture.decompose` (architecture is now its own sibling machine with its
1083
- > own memory scope, not nested under `design`). The `todoFile` var and the
1084
- > `prose` mode are both gone — there is no more free-form plan file. As with
1085
- > every rename above, an in-flight process resting at one of the old names can
1086
- > no longer be resumed; `gtd abandon` it (or finish it on the pre-upgrade
1087
- > workflow version) before upgrading.
1124
+ > own memory scope, not nested under `design`). The `prose` mode is gone and
1125
+ > there is no more free-form _plan_ file — `todoFile` itself came back later
1126
+ > with a different job: `idle`'s own mode-less `file:` hint, gtd's sketch pad
1127
+ > that no state writes or reads. As with every rename above, an in-flight
1128
+ > process resting at one of the old names can no longer be resumed;
1129
+ > `gtd abandon` it (or finish it on the pre-upgrade workflow version) before
1130
+ > upgrading.
1131
+
1132
+ > **Upgrading a `workflow:` that still references `build.addressing`?** That
1133
+ > state is REMOVED, not renamed — the implementer's own follow-through on review
1134
+ > feedback is gone outright, since an actionable review round is now re-planned
1135
+ > from scratch through a new root-level `re-unwind` state (reverting the human's
1136
+ > hand-edit) instead of being built upon. A non-actionable round (an approving
1137
+ > remark with no code edit) short-circuits straight to `build.squashing` instead
1138
+ > of spending a lap on nothing. As with every rename above, an in-flight process
1139
+ > resting at `build.addressing` can no longer be resumed after upgrading;
1140
+ > `gtd abandon` it (or finish it on the pre-upgrade workflow version) first.
1088
1141
 
1089
1142
  ### Variables
1090
1143
 
@@ -1197,7 +1250,14 @@ separator), symbols over a `qa`-mode file's open questions plus "pick this
1197
1250
  option"/"uncheck this option" code actions on each option — offered anywhere on
1198
1251
  the option's list item, including any wrapped continuation lines, not just its
1199
1252
  own `- [ ]` line — diagnostics for both (live as you edit), and a
1200
- `gtd.openSteeringFile` command that jumps to the current state's steering file.
1253
+ `gtd.openSteeringFile` command that jumps to the current state's steering file —
1254
+ including `idle`, whose `todoFile` hint gives the one keybinding an answer even
1255
+ before a process has started. The command only names that path — it never
1256
+ stat-checks or creates it — so on a repo that has never run gtd, `.gtd/` may not
1257
+ exist yet and editors differ on opening a file whose parent directory is missing
1258
+ (an empty buffer that creates it on save vs. refusing the path outright); this
1259
+ bites only the very first sketch in a fresh repo, since the workflow's own check
1260
+ scripts create the state directory on the first `gtd next`/`gtd land`.
1201
1261
 
1202
1262
  It is config-driven via each state's `file:`/`mode:`, and falls back to basename
1203
1263
  dispatch (`REVIEW.md` → `review`) with no config in sight. `qa` and `review` are