@pmelab/gtd 2.3.0 → 2.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 +67 -46
- package/dist/gtd.bundle.mjs +102 -18
- package/package.json +1 -1
- package/schema.json +3 -0
package/README.md
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
> in the first place. Now I have something that actually helps me.
|
|
6
6
|
|
|
7
7
|
A git-aware CLI that drives a turn-taking loop between a human and an autonomous
|
|
8
|
-
coding agent: capture an idea, grill it into a plan,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
into the project's own docs,
|
|
12
|
-
conventional-commits commit at the
|
|
8
|
+
coding agent: capture an idea, grill it into a product-level plan, grill that
|
|
9
|
+
into a technical architecture, decompose it into work packages, execute with
|
|
10
|
+
parallel subagents, test, agentically review each package, walk a human through
|
|
11
|
+
a review, distill durable lessons from the cycle into the project's own docs,
|
|
12
|
+
and finally squash the whole cycle into one conventional-commits commit at the
|
|
13
|
+
end.
|
|
13
14
|
|
|
14
15
|
Internally, gtd is a **pure fold** over git history. The decision core
|
|
15
16
|
(`src/Machine.ts`) is a single IO-free function, `resolve(events)` — **no
|
|
@@ -19,7 +20,7 @@ merge-base with the default branch (whole-history fallback when there is no
|
|
|
19
20
|
default branch, when HEAD equals the merge-base, or when there is no merge-base)
|
|
20
21
|
plus the working tree, turns them into a `COMMIT[]` + single terminal `RESOLVE`
|
|
21
22
|
event stream, and folds them through the machine. The fold lands on exactly
|
|
22
|
-
**one** of
|
|
23
|
+
**one** of 21 states, plus which actor (human or agent) is awaited there. A
|
|
23
24
|
single call resolves to a single state.
|
|
24
25
|
|
|
25
26
|
Steering is entirely **machine-authored commit subjects** — there are no marker
|
|
@@ -28,7 +29,8 @@ files, sentinels, or auto-advance tails to parse. A turn commit looks like
|
|
|
28
29
|
the machine performs itself between turns) looks like `gtd: tests green`.
|
|
29
30
|
`src/Subjects.ts` is the closed grammar both the machine and the edge read.
|
|
30
31
|
|
|
31
|
-
All workflow state lives under **`.gtd/`**: the plan (`.gtd/TODO.md`),
|
|
32
|
+
All workflow state lives under **`.gtd/`**: the product plan (`.gtd/TODO.md`),
|
|
33
|
+
the technical architecture it converges into (`.gtd/ARCHITECTURE.md`), work
|
|
32
34
|
packages (`.gtd/01-…/`), review records (`.gtd/REVIEW.md`, `.gtd/FEEDBACK.md`),
|
|
33
35
|
and loop bookkeeping (`.gtd/ERRORS.md`, `.gtd/HEALTH.md`, `.gtd/LEARNINGS.md`,
|
|
34
36
|
`.gtd/SQUASH_MSG.md`). One rule follows for every agent in the loop: **never
|
|
@@ -56,9 +58,10 @@ An agent loop is a two-beat protocol repeated forever:
|
|
|
56
58
|
act, then go back to step 1; at a pending checkpoint (`prompt` is null) go
|
|
57
59
|
straight back to step 1.
|
|
58
60
|
|
|
59
|
-
A human acts by editing files (answering questions in `.gtd/TODO.md
|
|
60
|
-
`.gtd/REVIEW.md`, fixing code) and then
|
|
61
|
-
as their turn and hand control back to
|
|
61
|
+
A human acts by editing files (answering questions in `.gtd/TODO.md` or
|
|
62
|
+
`.gtd/ARCHITECTURE.md`, annotating `.gtd/REVIEW.md`, fixing code) and then
|
|
63
|
+
running `gtd step` to capture the edit as their turn and hand control back to
|
|
64
|
+
the agent side of the loop.
|
|
62
65
|
|
|
63
66
|
```bash
|
|
64
67
|
gtd step-agent # advance the machine's own bookkeeping
|
|
@@ -166,8 +169,8 @@ invocation authored (oldest→newest), then a final `state: <state>` line:
|
|
|
166
169
|
|
|
167
170
|
```
|
|
168
171
|
committed: gtd(human): grilling
|
|
169
|
-
committed: gtd:
|
|
170
|
-
state:
|
|
172
|
+
committed: gtd: architecting
|
|
173
|
+
state: architecting
|
|
171
174
|
```
|
|
172
175
|
|
|
173
176
|
`--json` emits `{state, actions, commits}` instead (see
|
|
@@ -296,9 +299,9 @@ single-line JSON output instead of plain text.
|
|
|
296
299
|
|
|
297
300
|
```json
|
|
298
301
|
{
|
|
299
|
-
"state": "
|
|
302
|
+
"state": "architecting",
|
|
300
303
|
"actions": ["capture the human turn as \"gtd(human): grilling\""],
|
|
301
|
-
"commits": ["gtd(human): grilling", "gtd:
|
|
304
|
+
"commits": ["gtd(human): grilling", "gtd: architecting"]
|
|
302
305
|
}
|
|
303
306
|
```
|
|
304
307
|
|
|
@@ -429,9 +432,9 @@ GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop
|
|
|
429
432
|
|
|
430
433
|
## States & subjects overview
|
|
431
434
|
|
|
432
|
-
`resolve()` lands on exactly one of **
|
|
433
|
-
`planning`, `building`, `testing`, `fixing`, `escalate`,
|
|
434
|
-
`close-package`, `review`, `await-review`, `done`, `learning`,
|
|
435
|
+
`resolve()` lands on exactly one of **21 states**: `grilling`, `architecting`,
|
|
436
|
+
`grilled`, `planning`, `building`, `testing`, `fixing`, `escalate`,
|
|
437
|
+
`agentic-review`, `close-package`, `review`, `await-review`, `done`, `learning`,
|
|
435
438
|
`await-learning-review`, `learning-apply`, `learning-applied`, `squashing`,
|
|
436
439
|
`idle`, `health-check`, `health-fixing`. Each state has a fixed awaited actor
|
|
437
440
|
(see `awaitedActor` in `src/Machine.ts`): `idle`, `escalate`, `await-review`,
|
|
@@ -448,7 +451,8 @@ The closed set of gates:
|
|
|
448
451
|
|
|
449
452
|
| Gate | Authored by |
|
|
450
453
|
| ---------------- | ------------------------------------------------------------------ |
|
|
451
|
-
| `grilling` | human (answers) / agent (plan iteration)
|
|
454
|
+
| `grilling` | human (answers) / agent (product-plan iteration) |
|
|
455
|
+
| `architecting` | human (answers) / agent (architecture iteration) |
|
|
452
456
|
| `grilled` | agent (converged, ready to decompose) |
|
|
453
457
|
| `building` | agent (package work, or human feedback while agent is out of turn) |
|
|
454
458
|
| `fixing` | agent (test-fix or review-fix round) |
|
|
@@ -463,8 +467,8 @@ The closed set of gates:
|
|
|
463
467
|
### Routing commits — `gtd: <phase>`
|
|
464
468
|
|
|
465
469
|
Bookkeeping the machine authors itself between turns, never a turn a human or
|
|
466
|
-
agent "wins": `gtd:
|
|
467
|
-
`gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
|
|
470
|
+
agent "wins": `gtd: architecting`, `gtd: grilled`, `gtd: planning`,
|
|
471
|
+
`gtd: tests green`, `gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
|
|
468
472
|
`gtd: review feedback`, `gtd: done`, `gtd: squash template`,
|
|
469
473
|
`gtd: reviewing <hash>` (parameterized, from `gtd review`), `gtd: health-check`,
|
|
470
474
|
`gtd: health-fix`, `gtd: learning template`, `gtd: learning drafted`,
|
|
@@ -477,25 +481,39 @@ this matters on upgrade.
|
|
|
477
481
|
|
|
478
482
|
## Workflow walkthroughs
|
|
479
483
|
|
|
480
|
-
### Grilling
|
|
484
|
+
### Grilling: two phases, product then architecture
|
|
481
485
|
|
|
482
486
|
A dirty tree at a boundary HEAD (a fresh idea, sketched in a file or just left
|
|
483
487
|
as pending code) is captured in **one** human turn: `gtd step` commits
|
|
484
488
|
everything pending as `gtd(human): grilling` — nothing is reverted or seeded,
|
|
485
489
|
the captured files stay in history. `gtd next` hands the agent that turn's diff;
|
|
486
|
-
the agent develops `.gtd/TODO.md` into a concrete plan **in
|
|
487
|
-
|
|
488
|
-
`.gtd/TODO.md`
|
|
490
|
+
the agent develops `.gtd/TODO.md` into a concrete **product-level** plan **in
|
|
491
|
+
one turn** — user-facing decisions only, no architecture — proposing a
|
|
492
|
+
**suggested default** for every open question, and leaves `.gtd/TODO.md`
|
|
493
|
+
uncommitted for `gtd(agent): grilling`.
|
|
489
494
|
|
|
490
495
|
There are no markers to answer — the human either:
|
|
491
496
|
|
|
492
497
|
- **Accepts the suggested defaults**: runs a clean `gtd step` at the answer
|
|
493
|
-
gate. An empty `gtd(human): grilling` turn plus routing `gtd:
|
|
494
|
-
automatically
|
|
498
|
+
gate. An empty `gtd(human): grilling` turn plus routing `gtd: architecting`
|
|
499
|
+
lands automatically — `.gtd/ARCHITECTURE.md` is seeded from the converged
|
|
500
|
+
`.gtd/TODO.md` content and `.gtd/TODO.md` is deleted, in that one commit.
|
|
495
501
|
- **Edits `.gtd/TODO.md`** with real answers, then runs `gtd step`, which
|
|
496
502
|
captures the edit as a fresh `gtd(human): grilling` turn and hands it back to
|
|
497
503
|
the agent for another round.
|
|
498
504
|
|
|
505
|
+
Technical architecting works exactly the same way, one file later: the agent
|
|
506
|
+
develops `.gtd/ARCHITECTURE.md` into a concrete **technical** plan — file/module
|
|
507
|
+
structure, data model, tech-stack choices — and the human answers or accepts
|
|
508
|
+
defaults at the `architecting` gate. Accepting converges to `gtd: grilled` and
|
|
509
|
+
`gtd next` emits the decompose prompt (which now reads `.gtd/ARCHITECTURE.md`).
|
|
510
|
+
|
|
511
|
+
**Escape hatch for already-technical input:** if the human's initial dirty tree
|
|
512
|
+
already contains `.gtd/ARCHITECTURE.md` (their own technical sketch), `gtd step`
|
|
513
|
+
captures the entry turn as `gtd(human): architecting` directly, skipping product
|
|
514
|
+
grilling for that cycle entirely — no CLI flag needed, it's driven purely by
|
|
515
|
+
which steering file is present.
|
|
516
|
+
|
|
499
517
|
### Build lifecycle: budgets
|
|
500
518
|
|
|
501
519
|
Once decomposed, `.gtd/` holds ordered work packages. `gtd next` at
|
|
@@ -531,16 +549,16 @@ the threshold simply closes the package as usual.) Setting
|
|
|
531
549
|
`agenticReview: false` force-approves every package immediately.
|
|
532
550
|
|
|
533
551
|
A **do-nothing agent invocation** — `gtd step-agent` on a clean tree at ANY
|
|
534
|
-
agent-awaited rest whose move is a file artifact (`grilling`, `
|
|
535
|
-
`building`, `fixing`, `agentic-review`, `review`, `squashing` while
|
|
552
|
+
agent-awaited rest whose move is a file artifact (`grilling`, `architecting`,
|
|
553
|
+
`grilled`, `building`, `fixing`, `agentic-review`, `review`, `squashing` while
|
|
536
554
|
`.gtd/SQUASH_MSG.md` still holds the unmodified template, `learning` while
|
|
537
555
|
`.gtd/LEARNINGS.md` still holds the unmodified template, and `learning-apply`
|
|
538
556
|
unconditionally) — is inert: zero commits, no state consumed; `gtd next`
|
|
539
557
|
re-emits the same prompt. This is load-bearing for the loop protocol, whose
|
|
540
558
|
every iteration opens with `gtd step-agent` before the agent has acted: without
|
|
541
559
|
the guard that opening beat would author junk empty turns — and worse, consume
|
|
542
|
-
workflow state (an empty decompose turn would delete `.gtd/
|
|
543
|
-
packages written; an empty squashing turn would squash the cycle under the
|
|
560
|
+
workflow state (an empty decompose turn would delete `.gtd/ARCHITECTURE.md` with
|
|
561
|
+
no packages written; an empty squashing turn would squash the cycle under the
|
|
544
562
|
placeholder template). The same guards hold at the classification layer for
|
|
545
563
|
histories that already carry such turns: a `gtd(agent): grilled` HEAD only
|
|
546
564
|
routes to `gtd: planning` when packages exist, a `gtd(agent): review` HEAD only
|
|
@@ -549,8 +567,8 @@ routes to `gtd: awaiting review` when `.gtd/REVIEW.md` exists, and a squashing
|
|
|
549
567
|
deliberate exception is `health-fixing`, whose empty turn is meaningful (the
|
|
550
568
|
failure may have been environmental — the machine removes `.gtd/HEALTH.md` and
|
|
551
569
|
re-tests). Human gates are unaffected: an empty **human** turn stays a signal
|
|
552
|
-
(accept-defaults at grilling, clean approval at review,
|
|
553
|
-
at the learning review gate).
|
|
570
|
+
(accept-defaults at grilling/architecting, clean approval at review,
|
|
571
|
+
accept-the-draft-as-is at the learning review gate).
|
|
554
572
|
|
|
555
573
|
### Human review gate
|
|
556
574
|
|
|
@@ -622,15 +640,16 @@ With `squash: true` (the default), `gtd: done` (or, once learning has run,
|
|
|
622
640
|
to `gtd: squash template`, writing and committing a `.gtd/SQUASH_MSG.md`
|
|
623
641
|
template. `gtd next` then emits the squashing prompt: the agent overwrites
|
|
624
642
|
`.gtd/SQUASH_MSG.md` with a real conventional-commits message (drawing on
|
|
625
|
-
grilling-round decisions from history) and finishes its turn.
|
|
626
|
-
then performs the squash itself: `git reset --soft <base>` +
|
|
627
|
-
collapsing every intermediate `gtd: *` commit of the cycle into
|
|
628
|
-
any review-feedback detours, and the learning phase's own
|
|
629
|
-
ran: the squash base is the cycle's ORIGINAL start (the
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
the
|
|
633
|
-
|
|
643
|
+
grilling- and architecting-round decisions from history) and finishes its turn.
|
|
644
|
+
`gtd step-agent` then performs the squash itself: `git reset --soft <base>` +
|
|
645
|
+
`git commit`, collapsing every intermediate `gtd: *` commit of the cycle into
|
|
646
|
+
one — including any review-feedback detours, and the learning phase's own
|
|
647
|
+
commits if learning ran: the squash base is the cycle's ORIGINAL start (the
|
|
648
|
+
first grilling or, via the escape hatch, architecting turn since the previous
|
|
649
|
+
`gtd: done` boundary, or the `gtd: reviewing <hash>` anchor for an ad-hoc review
|
|
650
|
+
cycle), not the most recent re-grilling round — the collapse folds the whole
|
|
651
|
+
cycle into one, using the overwritten message's content verbatim (turn position,
|
|
652
|
+
not message content, triggers the squash). Doc edits made during
|
|
634
653
|
`learning-apply` survive in the squashed tree, not as their own commit. With
|
|
635
654
|
`squash: false`, `gtd: done` (or `gtd: learning applied`) is the resting
|
|
636
655
|
boundary and no template is ever written.
|
|
@@ -659,6 +678,7 @@ fix-attempt budget to zero.
|
|
|
659
678
|
| State | Awaits | Turn/routing subject at rest |
|
|
660
679
|
| ----------------------- | -------------- | ---------------------------------------------------------------- |
|
|
661
680
|
| `grilling` | human or agent | `gtd(human): grilling` / `gtd(agent): grilling` |
|
|
681
|
+
| `architecting` | human or agent | `gtd: architecting` / `gtd(agent): architecting` |
|
|
662
682
|
| `grilled` | agent | `gtd: grilled` |
|
|
663
683
|
| `planning` | agent | `.gtd/` modified |
|
|
664
684
|
| `building` | agent | `gtd: planning` / `gtd: package done` |
|
|
@@ -721,13 +741,14 @@ built-in defaults apply. Supported filenames (searched in this order):
|
|
|
721
741
|
phase entirely — independent of `squash`.
|
|
722
742
|
- **`models`** — model selection for the subagent-spawning states:
|
|
723
743
|
- `planning` — high-reasoning tier (default `claude-opus-4-8`), used by
|
|
724
|
-
`decompose` (the `grilled`/`planning` states), `grilling`, `
|
|
725
|
-
and `clean` (the `review`/`squashing`/`learning
|
|
744
|
+
`decompose` (the `grilled`/`planning` states), `grilling`, `architecting`,
|
|
745
|
+
`agentic-review`, and `clean` (the `review`/`squashing`/`learning`/
|
|
746
|
+
`learning-apply` states).
|
|
726
747
|
- `execution` — everyday tier (default `claude-sonnet-4-8`), used by
|
|
727
748
|
`building` and `fixing`.
|
|
728
749
|
- `states.*` — per-state overrides keyed by `decompose`, `grilling`,
|
|
729
|
-
`building`, `fixing`, `agentic-review`, `clean`. Unknown
|
|
730
|
-
**rejected**.
|
|
750
|
+
`architecting`, `building`, `fixing`, `agentic-review`, `clean`. Unknown
|
|
751
|
+
`states` keys are **rejected**.
|
|
731
752
|
- **`$schema`** (string, optional) — stripped before validation, so it never
|
|
732
753
|
counts as an unknown key. Point it at the published schema for editor-backed
|
|
733
754
|
autocompletion. A `schema.json` is generated from the config schema at build
|
|
@@ -815,7 +836,7 @@ models:
|
|
|
815
836
|
### Decompose
|
|
816
837
|
|
|
817
838
|
The Grilled/Planning states spawn a planning-model subagent that breaks
|
|
818
|
-
`.gtd/
|
|
839
|
+
`.gtd/ARCHITECTURE.md` into executable work packages under `.gtd/`:
|
|
819
840
|
|
|
820
841
|
```
|
|
821
842
|
.gtd/
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -367039,6 +367039,7 @@ var Cwd = class _Cwd extends Context_exports.Tag("Cwd")() {
|
|
|
367039
367039
|
var stateTier = {
|
|
367040
367040
|
decompose: "planning",
|
|
367041
367041
|
grilling: "planning",
|
|
367042
|
+
architecting: "planning",
|
|
367042
367043
|
building: "execution",
|
|
367043
367044
|
fixing: "execution",
|
|
367044
367045
|
"agentic-review": "planning",
|
|
@@ -367057,6 +367058,7 @@ var DEFAULT_REVIEW_THRESHOLD = 3;
|
|
|
367057
367058
|
var ModelStatesSchema = Schema_exports.Struct({
|
|
367058
367059
|
decompose: Schema_exports.optional(Schema_exports.String),
|
|
367059
367060
|
grilling: Schema_exports.optional(Schema_exports.String),
|
|
367061
|
+
architecting: Schema_exports.optional(Schema_exports.String),
|
|
367060
367062
|
building: Schema_exports.optional(Schema_exports.String),
|
|
367061
367063
|
fixing: Schema_exports.optional(Schema_exports.String),
|
|
367062
367064
|
"agentic-review": Schema_exports.optional(Schema_exports.String),
|
|
@@ -387758,6 +387760,7 @@ var formatFile = (path16) => Effect_exports.gen(function* () {
|
|
|
387758
387760
|
// src/Subjects.ts
|
|
387759
387761
|
var turnSubject = (actor, gate) => `gtd(${actor}): ${gate}`;
|
|
387760
387762
|
var ROUTING_SUBJECT = {
|
|
387763
|
+
architecting: "gtd: architecting",
|
|
387761
387764
|
grilled: "gtd: grilled",
|
|
387762
387765
|
planning: "gtd: planning",
|
|
387763
387766
|
"tests-green": "gtd: tests green",
|
|
@@ -387778,6 +387781,7 @@ var reviewingSubject = (baseHash) => `gtd: reviewing ${baseHash}`;
|
|
|
387778
387781
|
var TURN_RE = /^gtd\((human|agent)\): (.+)$/;
|
|
387779
387782
|
var TURN_GATES = /* @__PURE__ */ new Set([
|
|
387780
387783
|
"grilling",
|
|
387784
|
+
"architecting",
|
|
387781
387785
|
"grilled",
|
|
387782
387786
|
"building",
|
|
387783
387787
|
"fixing",
|
|
@@ -387822,6 +387826,7 @@ var parseSubject = (subject) => {
|
|
|
387822
387826
|
// src/Events.ts
|
|
387823
387827
|
var GTD_DIR = ".gtd";
|
|
387824
387828
|
var TODO_FILE = `${GTD_DIR}/TODO.md`;
|
|
387829
|
+
var ARCHITECTURE_FILE = `${GTD_DIR}/ARCHITECTURE.md`;
|
|
387825
387830
|
var REVIEW_FILE = `${GTD_DIR}/REVIEW.md`;
|
|
387826
387831
|
var FEEDBACK_FILE = `${GTD_DIR}/FEEDBACK.md`;
|
|
387827
387832
|
var ERRORS_FILE = `${GTD_DIR}/ERRORS.md`;
|
|
@@ -387834,6 +387839,7 @@ var DONE_SUBJECT = "gtd: done";
|
|
|
387834
387839
|
var WORKFLOW_FILE_EXCLUDES = [GTD_DIR];
|
|
387835
387840
|
var GATE_OWN_STEERING_FILE = {
|
|
387836
387841
|
grilling: TODO_FILE,
|
|
387842
|
+
architecting: ARCHITECTURE_FILE,
|
|
387837
387843
|
review: REVIEW_FILE
|
|
387838
387844
|
};
|
|
387839
387845
|
var SQUASH_OR_LEARNING_ROUTING_PHASES = /* @__PURE__ */ new Set([
|
|
@@ -388037,6 +388043,7 @@ var gatherEvents = (invoker) => (
|
|
|
388037
388043
|
const gtdModified = entries2.some((e7) => isPackagePath(e7.path));
|
|
388038
388044
|
const codeDirty = entries2.some((e7) => !isGtdPath(e7.path));
|
|
388039
388045
|
const todoExists = yield* fs9.exists(resolve5(TODO_FILE));
|
|
388046
|
+
const architectureExists = yield* fs9.exists(resolve5(ARCHITECTURE_FILE));
|
|
388040
388047
|
const reviewPresent = yield* fs9.exists(resolve5(REVIEW_FILE));
|
|
388041
388048
|
const feedbackPresent = yield* fs9.exists(resolve5(FEEDBACK_FILE));
|
|
388042
388049
|
const errorsPresent = yield* fs9.exists(resolve5(ERRORS_FILE));
|
|
@@ -388051,6 +388058,7 @@ var gatherEvents = (invoker) => (
|
|
|
388051
388058
|
const reviewCommitted = reviewTrackedAtHead && workingTreeClean;
|
|
388052
388059
|
const reviewDirty = reviewTrackedAtHead && !workingTreeClean;
|
|
388053
388060
|
const todoCommitted = todoExists && !isUncommitted(TODO_FILE);
|
|
388061
|
+
const architectureCommitted = architectureExists && !isUncommitted(ARCHITECTURE_FILE);
|
|
388054
388062
|
const pendingErrorsDeletion = entries2.some(
|
|
388055
388063
|
(e7) => e7.path === ERRORS_FILE && e7.status.includes("D")
|
|
388056
388064
|
);
|
|
@@ -388085,7 +388093,7 @@ var gatherEvents = (invoker) => (
|
|
|
388085
388093
|
}
|
|
388086
388094
|
const isGrillingTurn = (message) => {
|
|
388087
388095
|
const parsed = parseSubject(subjectOf(message));
|
|
388088
|
-
return parsed.kind === "turn" && parsed.gate === "grilling";
|
|
388096
|
+
return parsed.kind === "turn" && (parsed.gate === "grilling" || parsed.gate === "architecting");
|
|
388089
388097
|
};
|
|
388090
388098
|
const firstGrilling = currentCycle.find((c7) => isGrillingTurn(c7.message));
|
|
388091
388099
|
const lastAwaitingReview = (() => {
|
|
@@ -388133,7 +388141,7 @@ var gatherEvents = (invoker) => (
|
|
|
388133
388141
|
const squashCycle = squashHistory.slice(prevDoneIdx + 1, lastDoneIdxForSquash + 1);
|
|
388134
388142
|
const isGrillingTurnSubject = (subject) => {
|
|
388135
388143
|
const parsed = parseSubject(subject);
|
|
388136
|
-
return parsed.kind === "turn" && parsed.gate === "grilling";
|
|
388144
|
+
return parsed.kind === "turn" && (parsed.gate === "grilling" || parsed.gate === "architecting");
|
|
388137
388145
|
};
|
|
388138
388146
|
const isReviewingAnchor = (subject) => {
|
|
388139
388147
|
const parsed = parseSubject(subject);
|
|
@@ -388213,6 +388221,8 @@ var gatherEvents = (invoker) => (
|
|
|
388213
388221
|
...headTurnReviewSubstantive !== void 0 ? { headTurnReviewSubstantive } : {},
|
|
388214
388222
|
todoExists,
|
|
388215
388223
|
todoCommitted,
|
|
388224
|
+
architectureExists,
|
|
388225
|
+
architectureCommitted,
|
|
388216
388226
|
packagesPresent: packages.length > 0,
|
|
388217
388227
|
reviewPresent,
|
|
388218
388228
|
feedbackPresent,
|
|
@@ -388272,6 +388282,7 @@ var SQUASH_TEMPLATE = [
|
|
|
388272
388282
|
"Longer description of the change, if needed.",
|
|
388273
388283
|
""
|
|
388274
388284
|
].join("\n");
|
|
388285
|
+
var ARCHITECTURE_SEED_BANNER = "<!-- gtd: seeded from the converged product plan (.gtd/TODO.md); decide the technical/architectural questions below. -->\n\n";
|
|
388275
388286
|
var LEARNING_TEMPLATE = [
|
|
388276
388287
|
"<!-- gtd: replace this file's content with the actual distilled learnings for this cycle. -->",
|
|
388277
388288
|
"<!-- Keep only durable, generalizable lessons \u2014 delete anything that's a one-off detail. -->",
|
|
@@ -388290,22 +388301,38 @@ var perform = (action) => (
|
|
|
388290
388301
|
const resolve5 = (p4) => join10(root2, p4);
|
|
388291
388302
|
const ensureGtdDir = fs9.makeDirectory(resolve5(GTD_DIR), { recursive: true }).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388292
388303
|
switch (action.kind) {
|
|
388293
|
-
// Capture a human/agent turn: format the pending TODO.md
|
|
388294
|
-
// then commit-all under `gtd(<actor>): <gate>` (--allow-empty).
|
|
388304
|
+
// Capture a human/agent turn: format the pending TODO.md/ARCHITECTURE.md
|
|
388305
|
+
// (best-effort), then commit-all under `gtd(<actor>): <gate>` (--allow-empty).
|
|
388295
388306
|
case "captureTurn": {
|
|
388296
388307
|
const todoExists = yield* fs9.exists(resolve5(TODO_FILE));
|
|
388297
388308
|
if (todoExists) {
|
|
388298
388309
|
yield* formatFile(resolve5(TODO_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388299
388310
|
}
|
|
388311
|
+
const architectureExists = yield* fs9.exists(resolve5(ARCHITECTURE_FILE));
|
|
388312
|
+
if (architectureExists) {
|
|
388313
|
+
yield* formatFile(resolve5(ARCHITECTURE_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388314
|
+
}
|
|
388300
388315
|
yield* git.commitAllWithPrefix(turnSubject(action.actor, action.gate));
|
|
388301
388316
|
return { stop: false };
|
|
388302
388317
|
}
|
|
388303
388318
|
// Routing bookkeeping: delete the flagged files FIRST so their removal
|
|
388304
388319
|
// lands in this same commit, then commit-all under `subject`.
|
|
388320
|
+
// `seedArchitectureFromTodo` instead reads TODO.md, writes it (with a
|
|
388321
|
+
// scaffold banner) as ARCHITECTURE.md, and deletes TODO.md — the
|
|
388322
|
+
// grilling→architecting hand-off, in this same commit.
|
|
388305
388323
|
case "commitRouting": {
|
|
388306
|
-
if (action.
|
|
388324
|
+
if (action.seedArchitectureFromTodo === true) {
|
|
388325
|
+
const todoContent = yield* fs9.readFileString(resolve5(TODO_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.succeed("")));
|
|
388326
|
+
yield* ensureGtdDir;
|
|
388327
|
+
yield* fs9.writeFileString(
|
|
388328
|
+
resolve5(ARCHITECTURE_FILE),
|
|
388329
|
+
ARCHITECTURE_SEED_BANNER + todoContent
|
|
388330
|
+
);
|
|
388307
388331
|
yield* fs9.remove(resolve5(TODO_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388308
388332
|
}
|
|
388333
|
+
if (action.removeArchitecture === true) {
|
|
388334
|
+
yield* fs9.remove(resolve5(ARCHITECTURE_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388335
|
+
}
|
|
388309
388336
|
if (action.removeReview === true) {
|
|
388310
388337
|
yield* fs9.remove(resolve5(REVIEW_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388311
388338
|
}
|
|
@@ -388467,6 +388494,8 @@ var DEFAULT_PAYLOAD = {
|
|
|
388467
388494
|
headTurnIsEmpty: false,
|
|
388468
388495
|
todoExists: false,
|
|
388469
388496
|
todoCommitted: false,
|
|
388497
|
+
architectureExists: false,
|
|
388498
|
+
architectureCommitted: false,
|
|
388470
388499
|
packagesPresent: false,
|
|
388471
388500
|
reviewPresent: false,
|
|
388472
388501
|
feedbackPresent: false,
|
|
@@ -388556,6 +388585,9 @@ var learningFileConflictRules = [
|
|
|
388556
388585
|
var isReviewPackagesConflict = (p4) => p4.reviewPresent && p4.packagesPresent;
|
|
388557
388586
|
var isReviewCommittedTodoConflict = (p4) => p4.reviewPresent && p4.todoCommitted;
|
|
388558
388587
|
var isUncommittedReviewWithTodoConflict = (p4) => p4.reviewPresent && !(p4.reviewCommitted || p4.reviewDirty) && p4.todoExists;
|
|
388588
|
+
var isReviewCommittedArchitectureConflict = (p4) => p4.reviewPresent && p4.architectureCommitted;
|
|
388589
|
+
var isUncommittedReviewWithArchitectureConflict = (p4) => p4.reviewPresent && !(p4.reviewCommitted || p4.reviewDirty) && p4.architectureExists;
|
|
388590
|
+
var isTodoArchitectureConflict = (p4) => p4.todoExists && p4.architectureExists;
|
|
388559
388591
|
var isFeedbackReviewConflict = (p4) => p4.feedbackPresent && p4.reviewPresent;
|
|
388560
388592
|
var isFeedbackWithoutPackages = (p4) => p4.feedbackPresent && !p4.packagesPresent;
|
|
388561
388593
|
var isErrorsFeedbackConflict = (p4) => p4.errorsPresent && p4.feedbackPresent;
|
|
@@ -388571,6 +388603,15 @@ var reviewAndFeedbackRules = [
|
|
|
388571
388603
|
isViolated: isUncommittedReviewWithTodoConflict,
|
|
388572
388604
|
message: "uncommitted .gtd/REVIEW.md + .gtd/TODO.md"
|
|
388573
388605
|
},
|
|
388606
|
+
{
|
|
388607
|
+
isViolated: isReviewCommittedArchitectureConflict,
|
|
388608
|
+
message: ".gtd/REVIEW.md + committed .gtd/ARCHITECTURE.md"
|
|
388609
|
+
},
|
|
388610
|
+
{
|
|
388611
|
+
isViolated: isUncommittedReviewWithArchitectureConflict,
|
|
388612
|
+
message: "uncommitted .gtd/REVIEW.md + .gtd/ARCHITECTURE.md"
|
|
388613
|
+
},
|
|
388614
|
+
{ isViolated: isTodoArchitectureConflict, message: ".gtd/TODO.md + .gtd/ARCHITECTURE.md" },
|
|
388574
388615
|
{ isViolated: isFeedbackReviewConflict, message: ".gtd/FEEDBACK.md + .gtd/REVIEW.md" },
|
|
388575
388616
|
{ isViolated: isFeedbackWithoutPackages, message: ".gtd/FEEDBACK.md without packages" },
|
|
388576
388617
|
{ isViolated: isErrorsFeedbackConflict, message: ".gtd/ERRORS.md + .gtd/FEEDBACK.md" },
|
|
@@ -388636,15 +388677,30 @@ var classifyHead = (subject, flags) => {
|
|
|
388636
388677
|
kind: "mid-chain",
|
|
388637
388678
|
state: "grilling",
|
|
388638
388679
|
actor: "agent",
|
|
388639
|
-
action: {
|
|
388680
|
+
action: {
|
|
388681
|
+
kind: "commitRouting",
|
|
388682
|
+
subject: "gtd: architecting",
|
|
388683
|
+
seedArchitectureFromTodo: true
|
|
388684
|
+
}
|
|
388640
388685
|
} : { kind: "rest", state: "grilling", actor: "agent" };
|
|
388641
388686
|
}
|
|
388687
|
+
if (gate === "architecting") {
|
|
388688
|
+
if (actor === "agent") {
|
|
388689
|
+
return flags.headTurnIsEmpty ? { kind: "rest", state: "architecting", actor: "agent" } : { kind: "rest", state: "architecting", actor: "human" };
|
|
388690
|
+
}
|
|
388691
|
+
return flags.headTurnIsEmpty ? {
|
|
388692
|
+
kind: "mid-chain",
|
|
388693
|
+
state: "architecting",
|
|
388694
|
+
actor: "agent",
|
|
388695
|
+
action: { kind: "commitRouting", subject: "gtd: grilled" }
|
|
388696
|
+
} : { kind: "rest", state: "architecting", actor: "agent" };
|
|
388697
|
+
}
|
|
388642
388698
|
if (actor === "agent" && gate === "grilled") {
|
|
388643
388699
|
return flags.hasPackages ? {
|
|
388644
388700
|
kind: "mid-chain",
|
|
388645
388701
|
state: "grilled",
|
|
388646
388702
|
actor: "agent",
|
|
388647
|
-
action: { kind: "commitRouting", subject: "gtd: planning",
|
|
388703
|
+
action: { kind: "commitRouting", subject: "gtd: planning", removeArchitecture: true }
|
|
388648
388704
|
} : { kind: "rest", state: "grilled", actor: "agent" };
|
|
388649
388705
|
}
|
|
388650
388706
|
if (actor === "agent" && gate === "building") {
|
|
@@ -388718,6 +388774,8 @@ var classifyHead = (subject, flags) => {
|
|
|
388718
388774
|
}
|
|
388719
388775
|
if (parsed.kind === "routing") {
|
|
388720
388776
|
switch (parsed.phase) {
|
|
388777
|
+
case "architecting":
|
|
388778
|
+
return { kind: "rest", state: "architecting", actor: "agent" };
|
|
388721
388779
|
case "grilled":
|
|
388722
388780
|
return { kind: "rest", state: "grilled", actor: "agent" };
|
|
388723
388781
|
case "planning":
|
|
@@ -388764,6 +388822,7 @@ var classifyHead = (subject, flags) => {
|
|
|
388764
388822
|
};
|
|
388765
388823
|
var STATE_IS_OWN_GATE = /* @__PURE__ */ new Set([
|
|
388766
388824
|
"grilling",
|
|
388825
|
+
"architecting",
|
|
388767
388826
|
"grilled",
|
|
388768
388827
|
"building",
|
|
388769
388828
|
"fixing",
|
|
@@ -388781,6 +388840,7 @@ var GATE_OVERRIDES = {
|
|
|
388781
388840
|
var gateForState = (state) => STATE_IS_OWN_GATE.has(state) ? state : GATE_OVERRIDES[state] ?? "review";
|
|
388782
388841
|
var INERT_EMPTY_AGENT_GATES = /* @__PURE__ */ new Set([
|
|
388783
388842
|
"grilling",
|
|
388843
|
+
"architecting",
|
|
388784
388844
|
"grilled",
|
|
388785
388845
|
"building",
|
|
388786
388846
|
"fixing",
|
|
@@ -388883,6 +388943,9 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388883
388943
|
if (p4.todoExists) {
|
|
388884
388944
|
return { kind: "rest", state: "grilling", actor: "agent" };
|
|
388885
388945
|
}
|
|
388946
|
+
if (p4.architectureExists) {
|
|
388947
|
+
return { kind: "rest", state: "architecting", actor: "agent" };
|
|
388948
|
+
}
|
|
388886
388949
|
if (p4.packagesPresent && p4.packages.length > 0 && lastTurn?.actor === "agent" && lastTurn.gate === "building") {
|
|
388887
388950
|
return {
|
|
388888
388951
|
kind: "mid-chain",
|
|
@@ -388891,7 +388954,7 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388891
388954
|
action: { kind: "runTest", errorCount: 0, capReached: false }
|
|
388892
388955
|
};
|
|
388893
388956
|
}
|
|
388894
|
-
if (!p4.packagesPresent && !p4.reviewPresent && !p4.feedbackPresent && !p4.errorsPresent && !p4.healthPresent && !p4.todoExists) {
|
|
388957
|
+
if (!p4.packagesPresent && !p4.reviewPresent && !p4.feedbackPresent && !p4.errorsPresent && !p4.healthPresent && !p4.todoExists && !p4.architectureExists) {
|
|
388895
388958
|
return resolveIdleOrHealth(p4);
|
|
388896
388959
|
}
|
|
388897
388960
|
return corrupt();
|
|
@@ -388904,13 +388967,14 @@ var resolveIdleOrHealth = (p4) => {
|
|
|
388904
388967
|
var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
388905
388968
|
const context10 = buildContext(p4, counters);
|
|
388906
388969
|
const invoker = p4.invoker;
|
|
388907
|
-
const isDirtyBoundaryEntry = invoker === "human" && !p4.workingTreeClean && !p4.todoCommitted && !p4.packagesPresent && !p4.reviewPresent && !p4.feedbackPresent && !p4.errorsPresent && !p4.healthPresent && (parseSubject(head7).kind === "boundary" || head7 === "gtd: done");
|
|
388970
|
+
const isDirtyBoundaryEntry = invoker === "human" && !p4.workingTreeClean && !p4.todoCommitted && !p4.architectureCommitted && !p4.packagesPresent && !p4.reviewPresent && !p4.feedbackPresent && !p4.errorsPresent && !p4.healthPresent && (parseSubject(head7).kind === "boundary" || head7 === "gtd: done");
|
|
388908
388971
|
if (isDirtyBoundaryEntry) {
|
|
388972
|
+
const entryGate = p4.architectureExists ? "architecting" : "grilling";
|
|
388909
388973
|
return {
|
|
388910
|
-
state:
|
|
388974
|
+
state: entryGate,
|
|
388911
388975
|
actor: "human",
|
|
388912
388976
|
pending: false,
|
|
388913
|
-
edgeAction: { kind: "captureTurn", actor: "human", gate:
|
|
388977
|
+
edgeAction: { kind: "captureTurn", actor: "human", gate: entryGate },
|
|
388914
388978
|
context: context10
|
|
388915
388979
|
};
|
|
388916
388980
|
}
|
|
@@ -389020,9 +389084,14 @@ var predictTurn = (events) => {
|
|
|
389020
389084
|
const subject = baseline.action.kind === "commitRouting" ? baseline.action.subject : baseline.action.kind === "captureTurn" ? `gtd(${baseline.action.actor}): ${baseline.action.gate}` : null;
|
|
389021
389085
|
return { actor: baseline.actor, subject, state: baseline.state };
|
|
389022
389086
|
}
|
|
389023
|
-
const isDirtyBoundaryEntry = !payload.workingTreeClean && !payload.todoCommitted && !payload.packagesPresent && !payload.reviewPresent && !payload.feedbackPresent && !payload.errorsPresent && !payload.healthPresent && (parseSubject(head7).kind === "boundary" || head7 === "gtd: done");
|
|
389087
|
+
const isDirtyBoundaryEntry = !payload.workingTreeClean && !payload.todoCommitted && !payload.architectureCommitted && !payload.packagesPresent && !payload.reviewPresent && !payload.feedbackPresent && !payload.errorsPresent && !payload.healthPresent && (parseSubject(head7).kind === "boundary" || head7 === "gtd: done");
|
|
389024
389088
|
if (isDirtyBoundaryEntry) {
|
|
389025
|
-
|
|
389089
|
+
const entryGate = payload.architectureExists ? "architecting" : "grilling";
|
|
389090
|
+
return {
|
|
389091
|
+
actor: "human",
|
|
389092
|
+
subject: `gtd(human): ${entryGate}`,
|
|
389093
|
+
state: entryGate
|
|
389094
|
+
};
|
|
389026
389095
|
}
|
|
389027
389096
|
if (baseline.state === "idle") {
|
|
389028
389097
|
return { actor: "human", subject: null, state: "idle" };
|
|
@@ -389511,13 +389580,19 @@ var package_default = '<%\n const lines = ["", "### Package: `" + it.pkg.name +
|
|
|
389511
389580
|
var agent_turn_default = "Finish your turn by running `gtd step-agent`. Then run `gtd next` and follow\nits output \u2014 repeat this cycle as long as the output is addressed to you (the\nagent); when it awaits the human, stop and hand off.\n";
|
|
389512
389581
|
|
|
389513
389582
|
// src/prompts/grilling-agent.md
|
|
389514
|
-
var grilling_agent_default = '<%~ include("@header") %>\n\n`.gtd/TODO.md` holds the plan under development. Develop it into a concrete,\
|
|
389583
|
+
var grilling_agent_default = '<%~ include("@header") %>\n\n`.gtd/TODO.md` holds the plan under development. Develop it into a concrete,\nproduct-level plan **in this one turn** \u2014 use subagents / internal iteration\nto go as deep as needed; there is no further agent-only round after this one.\n\n**Scope: product and user-facing decisions only.** Do not decide\nimplementation details in this file \u2014 file/module structure, data models,\nlibrary or tech-stack choices, and other architecture questions belong to the\nnext phase (`.gtd/ARCHITECTURE.md`) and must not be treated as open questions\nhere.\n\n### Develop the plan\n\nSpawn a **planning-model subagent** using model `<%= it.model %>` to develop the plan.\nThe subagent works entirely by editing `.gtd/TODO.md`:\n\n1. **Explore the codebase before asking anything** \u2014 read the relevant files,\n tests, and docs so every question below is one the codebase genuinely\n cannot answer.\n2. **Replace the captured input / seed template with a real product plan** \u2014\n what to build and why, and the user-facing behavior it should have,\n grounded in the codebase. Leave *how* to build it for the next phase.\n3. **Iterate internally** (spawn further subagents, reconsider, cross-check)\n until the plan is as complete as it can get without human input. Do not\n leave this to a future round \u2014 there isn\'t one before the human is asked.\n4. For every remaining open question, write it near the top of the file with\n a **suggested default** \u2014 your best-guess answer, stated plainly, that the\n human can accept as-is. A question with no suggested default is incomplete.\n5. Leave `.gtd/TODO.md` **uncommitted** \u2014 the human\'s turn (`gtd step`) reads it\n next.\n<% if (it.context.turnDiff && it.context.turnDiff.trim()) { %>\n<%~ include("@diff", { heading: "Latest human input (answers / sketch / review feedback)", diff: it.context.turnDiff, fenceFor: it.fenceFor }) %>\n\nRead the diff above as **feedback, not finished work**:\n\n- Code changes are suggestions \u2014 fold them into the plan and re-implement them\n properly, including test coverage, rather than restoring them verbatim.\n- Code comments are positional feedback about the code at that location.\n- Plan-text changes are global feedback on the plan (or the reviewed work) as\n a whole.\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389515
389584
|
|
|
389516
389585
|
// src/prompts/grilling-answers.md
|
|
389517
|
-
var grilling_answers_default = '<%~ include("@header") %>\n\n`.gtd/TODO.md` holds the plan under development, with open questions written near\nthe top \u2014 each one carrying a suggested default.\n\nThis is a human gate; there is nothing for the agent to do.\n\nTell the user:\n\n- To answer a question, edit `.gtd/TODO.md` in place (replace the question\'s text\n with your answer, or annotate it), then run `gtd step`.\n- To accept **all** suggested defaults as-is, run `gtd step` with **no\n edits** \u2014 this converges the plan and moves on to
|
|
389586
|
+
var grilling_answers_default = '<%~ include("@header") %>\n\n`.gtd/TODO.md` holds the plan under development, with open questions written near\nthe top \u2014 each one carrying a suggested default.\n\nThis is a human gate; there is nothing for the agent to do.\n\nTell the user:\n\n- To answer a question, edit `.gtd/TODO.md` in place (replace the question\'s text\n with your answer, or annotate it), then run `gtd step`.\n- To accept **all** suggested defaults as-is, run `gtd step` with **no\n edits** \u2014 this converges the plan and moves on to technical architecting.\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389587
|
+
|
|
389588
|
+
// src/prompts/architecting-agent.md
|
|
389589
|
+
var architecting_agent_default = '<%~ include("@header") %>\n\n`.gtd/ARCHITECTURE.md` holds the technical plan under development \u2014 seeded\nfrom the converged product plan, or, if this is the very first turn on\nalready-technical input, written directly by the human. Develop it into a concrete,\nimplementation-ready technical plan **in this one turn** \u2014 use subagents /\ninternal iteration to go as deep as needed; there is no further agent-only\nround after this one.\n\n**Scope: technical/architectural decisions only.** Decide file/module\nstructure, data models, module boundaries, library or tech-stack choices, and\nerror-handling/concurrency strategy \u2014 the *how*, building on the *what*\nalready settled in this file\'s product content. Do not re-open or re-litigate\nproduct/user-facing decisions from the prior phase; treat them as settled\ncontext.\n\n### Develop the architecture\n\nSpawn a **planning-model subagent** using model `<%= it.model %>` to develop the\narchitecture. The subagent works entirely by editing `.gtd/ARCHITECTURE.md`:\n\n1. **Explore the codebase before asking anything** \u2014 read the relevant files,\n tests, and docs so every question below is one the codebase genuinely\n cannot answer.\n2. **Replace the seeded/captured content with a real architecture** \u2014 the\n files to change, module/data-model structure, and why, grounded in the\n codebase.\n3. **Iterate internally** (spawn further subagents, reconsider, cross-check)\n until the architecture is as complete as it can get without human input.\n Do not leave this to a future round \u2014 there isn\'t one before the human is\n asked.\n4. For every remaining open question, write it near the top of the file with\n a **suggested default** \u2014 your best-guess answer, stated plainly, that the\n human can accept as-is. A question with no suggested default is incomplete.\n5. Leave `.gtd/ARCHITECTURE.md` **uncommitted** \u2014 the human\'s turn (`gtd step`)\n reads it next.\n<% if (it.context.turnDiff && it.context.turnDiff.trim()) { %>\n<%~ include("@diff", { heading: "Latest human input (answers / sketch / review feedback)", diff: it.context.turnDiff, fenceFor: it.fenceFor }) %>\n\nRead the diff above as **feedback, not finished work**:\n\n- Code changes are suggestions \u2014 fold them into the architecture and\n re-implement them properly, including test coverage, rather than restoring\n them verbatim.\n- Code comments are positional feedback about the code at that location.\n- Plan-text changes are global feedback on the architecture (or the reviewed\n work) as a whole.\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389590
|
+
|
|
389591
|
+
// src/prompts/architecting-answers.md
|
|
389592
|
+
var architecting_answers_default = '<%~ include("@header") %>\n\n`.gtd/ARCHITECTURE.md` holds the technical plan under development, with open\nquestions written near the top \u2014 each one carrying a suggested default.\n\nThis is a human gate; there is nothing for the agent to do.\n\nTell the user:\n\n- To answer a question, edit `.gtd/ARCHITECTURE.md` in place (replace the\n question\'s text with your answer, or annotate it), then run `gtd step`.\n- To accept **all** suggested defaults as-is, run `gtd step` with **no\n edits** \u2014 this converges the architecture and moves on to decomposition.\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389518
389593
|
|
|
389519
389594
|
// src/prompts/decompose.md
|
|
389520
|
-
var decompose_default = '<%~ include("@header") %>\n\n`.gtd/
|
|
389595
|
+
var decompose_default = '<%~ include("@header") %>\n\n`.gtd/ARCHITECTURE.md` contains a converged architecture/technical plan.\nDecompose it into an ordered set of executable work packages stored in the\n`.gtd/` directory. If `.gtd/` already holds packages from an earlier turn,\nimmediately abort and raise an error.\n\nSpawn a **planning-model subagent** using model `<%= it.model %>` to perform the\ndecomposition. It creates numbered package directories, each holding numbered\ntask files:\n\n```\n.gtd/\n 01-<package-name>/\n 01-<task-name>.md\n 02-<task-name>.md\n 02-<package-name>/\n ...\n```\n\n**Rules for the subagent:**\n\n1. **Packages are sequential, in dependency order** \u2014 ordinal-prefixed\n directories (`01-`, `02-`, \u2026) execute in that order and the set is frozen\n once written. Order them so each package depends only on lower-numbered ones.\n\n2. **Each package is green on its own** \u2014 the test suite runs after every\n package. Never split a feature so the tree stays red until a later package\n lands.\n\n3. **Tasks within a package are parallel and file-disjoint** \u2014 all tasks in a\n package run simultaneously, each via one subagent, against the same working\n tree with no isolation. Two tasks that would touch the same file must be\n **merged** into one. If task B depends on task A, put them in separate\n packages.\n\n4. **Vertical slices, not horizontal** \u2014 each package is a thin, end-to-end\n slice that is demoable or verifiable on its own. Prefer many thin packages\n over few thick ones; never a "set up infrastructure" package.\n\n5. **Task files are self-contained** \u2014 each task `.md` includes a clear\n description of what to build, acceptance criteria as `- [ ] Criterion`\n checkboxes, the relevant file paths to examine, and any constraints or edge\n cases. It is the only context building agents will receive to work on the\n task.\n\n6. **Specs must never reference `.gtd/` files** \u2014 `.gtd/ARCHITECTURE.md` is\n consumed and **deleted** the moment decomposition completes, and every other file\n under `.gtd/` (including these task specs) is machine-managed workflow\n state. No task description, acceptance criterion, or constraint may require\n creating, preserving, updating, or checking any `.gtd/` file \u2014 such a\n criterion can never be satisfied and would derail the workflow.\n\n**DO NOT** commit any changes. This process runs within a larger orchestration\nthat depends on uncommitted changes.\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389521
389596
|
|
|
389522
389597
|
// src/prompts/building.md
|
|
389523
389598
|
var building_default = '<%~ include("@header") %>\n\nBuild the package described below by orchestrating the execution \u2014 you do not\nimplement the tasks yourself. Spawn **one subagent per task**, all in\n**parallel**, each using model `<%= it.model %>`:\n\n- **Context**: the task content only (it is self-contained).\n- **Fresh context**: each worker starts cold, with no shared history.\n- **Hands off `.gtd/`** (inline rule for workers): never create, edit, or\n delete anything under `.gtd/` \u2014 it is workflow state owned by the machine.\n If the task spec mentions a `.gtd/` file, skip that part.\n- **TDD discipline** (inline rules for workers):\n - Write ONE test \u2192 implement \u2192 pass \u2192 repeat (vertical slices).\n - **Do NOT** write all tests first then implement (horizontal slicing).\n - Tests verify behavior through public interfaces, not implementation details\n \u2014 a good test survives a refactor.\n\nWait for all workers to complete. **If any worker fails** (crash, timeout, error\n\u2014 not a test failure): report which tasks failed and ask the user whether to\nretry the failed tasks, skip and continue, or abort.\n\nLeave all changes uncommitted. An outside process handles that.\n<% if (it.context.packages[0]) { %>\n<%~ include("@package", { pkg: it.context.packages[0], fenceFor: it.fenceFor }) %>\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
@@ -389538,7 +389613,7 @@ var review_default = '<%~ include("@header") %>\n\nSpawn a **planning-model suba
|
|
|
389538
389613
|
var await_review_default = '<%~ include("@header") %>\n\n`.gtd/REVIEW.md` holds the review record for the completed work. This is a human\ngate; there is nothing for the agent to do.\n\nTell the user:\n\n- Read `.gtd/REVIEW.md` (and the underlying work it points at).\n- To **approve**: run `gtd step` with no edits, or only tick checkboxes in\n `.gtd/REVIEW.md` \u2014 either way ends the review with an approval.\n- To **request changes**: write substantive edits or annotations into\n `.gtd/REVIEW.md` (or the code) describing what\'s wrong, then run `gtd step` \u2014\n this sends the feedback back for another round.\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389539
389614
|
|
|
389540
389615
|
// src/prompts/squashing.md
|
|
389541
|
-
var squashing_default = '<%~ include("@header") %>\n\nThe process is **approved and done**. `.gtd/SQUASH_MSG.md` has already been\ncommitted with a template \u2014 your job is to overwrite it with the real\nconventional-commits squash message and finish your turn.\n\n### Step 1 \u2014 Extract decisions from grilling rounds\n\nScan the git history of recent `gtd: ...` / `gtd(agent): ...` /\n`gtd(human): ...` commits. Look for changes to `.gtd/TODO.md` \u2014 specifically the
|
|
389616
|
+
var squashing_default = '<%~ include("@header") %>\n\nThe process is **approved and done**. `.gtd/SQUASH_MSG.md` has already been\ncommitted with a template \u2014 your job is to overwrite it with the real\nconventional-commits squash message and finish your turn.\n\n### Step 1 \u2014 Extract decisions from grilling rounds\n\nScan the git history of recent `gtd: ...` / `gtd(agent): ...` /\n`gtd(human): ...` commits. Look for changes to `.gtd/TODO.md` and\n`.gtd/ARCHITECTURE.md` \u2014 specifically the `## Captured input` sections and any\nedits to plan/architecture text. Extract **key decisions, trade-offs, and\ndesign choices** made during grilling and architecting rounds. These will\nappear in the commit body so the history is self-documenting.\n\n### Step 2 \u2014 Draft the commit message\n\nDraft ONE conventional-commits message:\n\n```\ntype(scope): subject\n\nbody (explain the why \u2014 motivation, trade-offs, key decisions from grilling)\n```\n\n- **type**: `feat` / `fix` / `refactor` / `chore` / `docs` / `test`\n- **subject**: imperative mood, \u2264 72 characters, lowercase after the colon\n- **body**: include the important decisions / trade-offs from grilling\n sessions. Omit if there were no meaningful decisions to capture.\n\n### Step 3 \u2014 Overwrite .gtd/SQUASH_MSG.md\n\nReplace the **entire content** of `.gtd/SQUASH_MSG.md` (plain text, no markdown\nwrapper, no leftover template scaffolding) with the message from Step 2, then\nleave it uncommitted and finish your turn \u2014 `gtd step-agent` performs the\nsquash using this file\'s content.\n<% if (it.context.squashDiff && it.context.squashDiff.trim()) { %>\n<%= it.context.squashBase !== undefined ? "\\nSquash base: " + it.context.squashBase + "\\n" : "" %>\n<%~ include("@diff", { heading: "Full-process diff (`git diff " + (it.context.squashBase !== undefined ? it.context.squashBase : "<squashBase>") + " HEAD`)", diff: it.context.squashDiff, fenceFor: it.fenceFor }) %>\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389542
389617
|
|
|
389543
389618
|
// src/prompts/learning.md
|
|
389544
389619
|
var learning_default = '<%~ include("@header") %>\n\nThe process is **approved and done**, and headed for a squash. Before that\nhappens, `.gtd/LEARNINGS.md` has been committed with a template \u2014 your job is\nto overwrite it with the real, distilled learnings from this cycle so they\nsurvive the squash even though the granular history won\'t.\n\n### Step 1 \u2014 Walk the cycle\'s history\n\nScan the git history back to the cycle\'s start (the full-process diff is\ninlined below, and `git log` over the same range shows every `gtd: ...` /\n`gtd(agent): ...` / `gtd(human): ...` commit). Look specifically for:\n\n- **Test failures and fixes** \u2014 each `gtd: errors` round and the fix that\n followed it. What broke, and what actually made it pass?\n- **Review feedback** \u2014 human `.gtd/REVIEW.md` notes and `gtd: review\n feedback` detours. What did the human have to correct that the agent got\n wrong on its own?\n- **Health-check rounds** \u2014 any `gtd: health-check` / `gtd: health-fix`\n cycles. Environmental or systemic issues surfaced outside normal building?\n- **Grilling decisions** \u2014 `.gtd/TODO.md`\'s "## Captured input" sections and\n plan edits. Trade-offs or conventions the human specified that a future\n agent should already know.\n\n### Step 2 \u2014 Distill, don\'t transcribe\n\nFor each thing you found, ask: is this a **durable, generalizable lesson**\n(a convention, a gotcha, a pattern this project wants followed next time), or\na **one-off detail** specific to this change? Keep only the former. A future\nagent reading this should learn something that changes how it works on this\nproject, not a recap of what happened.\n\n### Step 3 \u2014 Overwrite .gtd/LEARNINGS.md\n\nReplace the **entire content** of `.gtd/LEARNINGS.md` with your distilled\nlearnings (plain markdown, no leftover template scaffolding). If nothing\ndurable surfaced this cycle, write a short explicit note saying so \u2014 don\'t\nleave the placeholder text in place. Leave the file uncommitted and finish\nyour turn; a human reviews it next before it\'s integrated into the project\'s\nown memory (CLAUDE.md/AGENTS.md/docs).\n<% if (it.context.squashDiff && it.context.squashDiff.trim()) { %>\n<%= it.context.squashBase !== undefined ? "\\nCycle base: " + it.context.squashBase + "\\n" : "" %>\n<%~ include("@diff", { heading: "Full-process diff (`git diff " + (it.context.squashBase !== undefined ? it.context.squashBase : "<squashBase>") + " HEAD`)", diff: it.context.squashDiff, fenceFor: it.fenceFor }) %>\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
@@ -389558,6 +389633,7 @@ var idle_default = "The repository is idle \u2014 no work cycle is in progress a
|
|
|
389558
389633
|
// src/Prompt.ts
|
|
389559
389634
|
var PROMPT_STATES = /* @__PURE__ */ new Set([
|
|
389560
389635
|
"grilling",
|
|
389636
|
+
"architecting",
|
|
389561
389637
|
"grilled",
|
|
389562
389638
|
"building",
|
|
389563
389639
|
"fixing",
|
|
@@ -389575,6 +389651,7 @@ var PROMPT_STATES = /* @__PURE__ */ new Set([
|
|
|
389575
389651
|
var isPromptState = (state) => PROMPT_STATES.has(state);
|
|
389576
389652
|
var MODEL_STATE = {
|
|
389577
389653
|
grilling: "grilling",
|
|
389654
|
+
architecting: "architecting",
|
|
389578
389655
|
grilled: "decompose",
|
|
389579
389656
|
building: "building",
|
|
389580
389657
|
fixing: "fixing",
|
|
@@ -389599,6 +389676,8 @@ eta.loadTemplate("@package", package_default);
|
|
|
389599
389676
|
eta.loadTemplate("@agent-turn", agent_turn_default);
|
|
389600
389677
|
eta.loadTemplate("@grilling-agent", grilling_agent_default);
|
|
389601
389678
|
eta.loadTemplate("@grilling-answers", grilling_answers_default);
|
|
389679
|
+
eta.loadTemplate("@architecting-agent", architecting_agent_default);
|
|
389680
|
+
eta.loadTemplate("@architecting-answers", architecting_answers_default);
|
|
389602
389681
|
eta.loadTemplate("@decompose", decompose_default);
|
|
389603
389682
|
eta.loadTemplate("@building", building_default);
|
|
389604
389683
|
eta.loadTemplate("@fixing", fixing_default);
|
|
@@ -389641,6 +389720,8 @@ var buildPrompt = (result, resolveModel = builtinResolveModel, output = "plain")
|
|
|
389641
389720
|
let templateName;
|
|
389642
389721
|
if (promptState === "grilling") {
|
|
389643
389722
|
templateName = result.actor === "human" ? "@grilling-answers" : "@grilling-agent";
|
|
389723
|
+
} else if (promptState === "architecting") {
|
|
389724
|
+
templateName = result.actor === "human" ? "@architecting-answers" : "@architecting-agent";
|
|
389644
389725
|
} else {
|
|
389645
389726
|
templateName = STATE_TEMPLATE[promptState];
|
|
389646
389727
|
}
|
|
@@ -389731,8 +389812,11 @@ var edgeActionHandlers = {
|
|
|
389731
389812
|
captureTurn: (a5) => `capture the ${a5.actor} turn as "gtd(${a5.actor}): ${a5.gate}"`,
|
|
389732
389813
|
commitRouting: (a5) => {
|
|
389733
389814
|
let msg = `commit routing as "${a5.subject}"`;
|
|
389815
|
+
if (a5.seedArchitectureFromTodo) {
|
|
389816
|
+
msg += " (seeding .gtd/ARCHITECTURE.md from .gtd/TODO.md)";
|
|
389817
|
+
}
|
|
389734
389818
|
const removed = [];
|
|
389735
|
-
if (a5.
|
|
389819
|
+
if (a5.removeArchitecture) removed.push(".gtd/ARCHITECTURE.md");
|
|
389736
389820
|
if (a5.removeReview) removed.push(".gtd/REVIEW.md");
|
|
389737
389821
|
if (a5.removeFeedback) removed.push(".gtd/FEEDBACK.md");
|
|
389738
389822
|
if (a5.removeHealth) removed.push(".gtd/HEALTH.md");
|
package/package.json
CHANGED