@pmelab/gtd 6.14.0 → 7.0.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 +17 -17
- package/dist/gtd.bundle.mjs +122 -137
- package/docs/cli.md +28 -25
- package/docs/configuration.md +55 -57
- package/docs/development.md +2 -1
- package/docs/upgrading.md +15 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,28 +49,28 @@ Or run without installing:
|
|
|
49
49
|
npx @pmelab/gtd
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
That's it — gtd ships the **unified** workflow as its **built-in default**, so a
|
|
53
|
+
state command works out of the box with no configuration at all.
|
|
54
|
+
|
|
55
|
+
Optionally, seed the settings a project usually tunes — run once:
|
|
53
56
|
|
|
54
57
|
```bash
|
|
55
58
|
gtd init
|
|
56
59
|
```
|
|
57
60
|
|
|
58
|
-
This writes a `.gtdrc.json`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
**no** default workflow: a state command run before `gtd init` fails, pointing
|
|
72
|
-
you back here. See [Configuration](docs/configuration.md#gtd-init) for the
|
|
73
|
-
template.
|
|
61
|
+
This writes a minimal `.gtdrc.json` seeding the one variable most projects
|
|
62
|
+
change — the test command (`vars.testCommand`, defaulting to `npm test`) — plus
|
|
63
|
+
a top-level `modes:` block suggesting **Prettier** as the steering-file
|
|
64
|
+
formatter (`npx prettier --write` for the built-in `qa`/`review` modes — format
|
|
65
|
+
only, so gtd still validates); edit or drop either freely (point `testCommand`
|
|
66
|
+
at your suite, swap Prettier for dprint or a script, delete a key). It writes
|
|
67
|
+
**no** `workflow:` key — the machine is built in — so review and commit the file
|
|
68
|
+
before your first `gtd step`. `gtd init` takes no argument and refuses to
|
|
69
|
+
clobber an existing config; it may also run in a plain parent directory (not a
|
|
70
|
+
git repo) to seed a shared config a nested repo picks up. To customize the
|
|
71
|
+
machine itself, add a `workflow:` key (there is no default fallback to merge
|
|
72
|
+
over — a `workflow:` is the whole definition). See
|
|
73
|
+
[Configuration](docs/configuration.md#gtd-init) for the details.
|
|
74
74
|
|
|
75
75
|
## How it works
|
|
76
76
|
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -190185,6 +190185,82 @@ const compileWorkflowConfig = (raw, configDir, rcModes, inlineFileRefs = true) =
|
|
|
190185
190185
|
};
|
|
190186
190186
|
};
|
|
190187
190187
|
//#endregion
|
|
190188
|
+
//#region src/workflows/unified.yaml
|
|
190189
|
+
var unified_default = "# The unified gtd workflow template — gtd's BUILT-IN DEFAULT workflow. When no\n# `workflow:` key is configured anywhere in the cwd→home config chain,\n# src/Config.ts runs this template directly, so a state command works with no\n# configuration at all. `gtd init` seeds only the settings a project tunes\n# (vars.testCommand + a modes: formatting suggestion), never the workflow\n# itself. See STATES.md §10 for the full walkthrough.\n#\n# Compiled through the exact same `compileWorkflowConfig` a user's `.gtdrc`\n# `workflow:` key goes through — no privileged code path\n# (src/workflows/templates.ts does the compiling). Every content string below\n# is INLINE (no `./`-relative file references): the bundled template ships\n# inside a single-file build (`dist/gtd.bundle.mjs`), so its content must\n# already be resolved at BUILD time. `renderInitConfig` (src/workflows/\n# templates.ts) can MATERIALIZE this inline source into a `.gtdrc.json`\n# `workflow:` value — the way to eject/customize the machine, and the hermetic\n# test fixture — but `gtd init` itself no longer writes the workflow.\n#\n# ── Four entry points behind a green-baseline gate, one shared tail ─────────\n#\n# EVERY entry first runs the test suite and only proceeds when it is GREEN — you\n# never start new work (or a review) on top of a red baseline. A red run halts\n# at a human `*-start-blocked` gate (fix the failures and re-run, exactly like\n# the `escalate` states), or is what `gtd fix` exists to repair.\n#\n# The initial `idle` state FORKS on which steering file the human creates,\n# routing into that flow's OWN start gate:\n#\n# * .gtd/REQUIREMENTS.md -> `adv-start-check` -> the ADVANCED flow (product +\n# technical Q&A, package decomposition, per-package parallel build +\n# agentic spec-review).\n# * anything else (e.g. .gtd/TODO.md) -> `start-check` -> the SIMPLE flow (one\n# grilling Q&A loop, a monolithic build, no decomposition, no agentic\n# review).\n#\n# A third entry, `gtd review <commitish>`, jumps to `review-start-check`\n# (reviewEntry) and, once green, to `reviewing` to review a foreign branch\n# through the same shared tail. A fourth, `gtd fix`, jumps to `fix-check`\n# (fixEntry): a red suite drops straight into the shared `fixing` loop and out\n# through the review + squash tail; a green suite is a no-op back to `idle`.\n#\n# All three converge at `reviewing` -> `await-review`. Ticking a REVIEW.md box\n# means only \"I reviewed this hunk\"; a COMMENT (not an unticked box) is what asks\n# for changes. Every human step at `await-review` goes to `review-deciding`,\n# which inspects the step and routes:\n# * no comment (every box ticked, no REVIEW.md note, no code edit) -> the diff\n# is a bare REVIEW.md deletion -> squashing -> done (the ONLY path to the\n# finale — the whole cycle collapses into one commit).\n# * any comment — a note in REVIEW.md OR a hand-edit to code — ->\n# review-deciding writes REVIEW_FEEDBACK.md -> feedback-building implements\n# it (completing any code the human hand-edited, never reverting their\n# lines) -> checking -> reviewing regenerates an INCREMENTAL REVIEW.md\n# (review-deciding carries `reviewBase: true`, so each feedback round's\n# review + checkout window covers only `last-review..HEAD`, i.e. the agent's\n# follow-through, not the human's own edit) -> await-review, looping until\n# sign-off.\n# Two dead ends never commit: the sign-off gate (src/program.ts) REFUSES a step\n# that leaves a box unticked with no comment (finish reviewing first) and a\n# deleted REVIEW.md (restore it and tick the boxes).\n#\n# The shared health segment (`checking`/`fixing`/`escalate`) serves the simple\n# build and the feedback loop — its green edge targets\n# `reviewing`. The advanced per-package loop keeps its OWN health triple\n# (`adv-checking`/`adv-fixing`/`adv-escalate`) because its green edge targets\n# the per-package `spec-review` gate instead.\n#\n# KNOWN LIMITATION: `on` pattern keys are NOT Eta templates — they keep the\n# LITERAL `.gtd/...` paths matching these vars' DEFAULT values. Repointing a\n# file var changes what templates read/write WITHOUT changing what the `on`\n# patterns match, desyncing the machine (see docs/configuration.md).\n\nvars:\n testCommand: npm test\n todoFile: .gtd/TODO.md\n requirementsFile: .gtd/REQUIREMENTS.md\n architectureFile: .gtd/ARCHITECTURE.md\n packagesDir: .gtd/packages\n nextFile: .gtd/NEXT.md\n reviewFile: .gtd/REVIEW.md\n reviewRawFile: .gtd/REVIEW_RAW.md\n reviewFeedbackFile: .gtd/REVIEW_FEEDBACK.md\n feedbackFile: .gtd/FEEDBACK.md\n specFeedbackFile: .gtd/SPEC_FEEDBACK.md\n commitMsgFile: .gtd/COMMIT_MSG.md\n # The two opaque model tiers every agent state draws from — repoint them here\n # (or via a top-level `.gtdrc` `vars:` key / a `GTD_VAR_plannerModel` env var)\n # to change every state on that tier at once. `plannerModel` (default \"smart\")\n # is the heavier tier for the one-shot planning/architecting/review turns;\n # `coderModel` (default \"base\") is the tier for the build/fix turns.\n plannerModel: smart\n coderModel: base\n\nstates:\n # ── Shared entry ────────────────────────────────────────────────────────\n idle:\n actor: human\n initial: true\n # Every human-gate `message:` below closes with the same rendered \"What\n # each change does next\" list, built from `it.edges` (the resting state's\n # own `on` edges — each edge's `describe:` is the single source of truth).\n message: |\n No active gtd cycle.\n\n To start one, create a steering file describing what you want built:\n\n - `.gtd/TODO.md` — a short sketch — starts the SIMPLE flow (plan, build,\n review).\n - `.gtd/REQUIREMENTS.md` — the product requirements — starts the ADVANCED\n flow (product + technical Q&A, package decomposition, parallel build,\n per-package agentic review).\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* .gtd/REQUIREMENTS.md\":\n to: adv-start-check\n describe: >-\n Save the product requirements to `.gtd/REQUIREMENTS.md` to start the\n ADVANCED flow — gtd first checks the test baseline is green, then the\n agent develops them through product then technical Q&A, decomposes the\n work into packages, and builds each in parallel (**adv-start-check**).\n \"* **\":\n to: start-check\n describe: >-\n Save a short sketch to `.gtd/TODO.md` (or any other change) to start\n the SIMPLE flow — gtd first checks the test baseline is green, then the\n agent reads it, explores the codebase, and develops it into a concrete\n implementation plan (**start-check**).\n\n # ── Green-baseline gate: simple flow ──────────────────────────────────────\n # Runs the suite before any planning starts. Its script is `checking`'s test\n # wrapper verbatim (red -> .gtd/FEEDBACK.md, green -> remove it); the `on`\n # rules turn that into \"halt at start-blocked\" vs \"proceed to planning\".\n start-check:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before starting new work; a red run\n # records .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": start-blocked\n \"M .gtd/FEEDBACK.md\": start-blocked\n \"D .gtd/FEEDBACK.md\": planning\n \"C\": planning\n\n start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start new work on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**start-check**). To repair the baseline as\n its own separate reviewed commit instead, abandon this start and run\n `gtd fix` from a clean `idle`.\n\n # ── Simple flow: plan-iteration loop, monolithic build ────────────────────\n planning:\n actor: agent\n file: <%= it.vars.todoFile %>\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.todoFile %>`, which this prompt tells you to develop.\n\n `<%= it.vars.todoFile %>` holds a short sketch of what to build — or, on a\n return lap, the plan you already wrote plus the human's edits and comments\n on it. Read it, explore the codebase, and develop it into a concrete\n implementation plan: the files to change, the approach, and the steps to\n take.\n\n Do NOT ask questions and do NOT add an \"Open Questions\" section — decide\n every open point yourself and write the plan as a set of concrete\n decisions. Where a decision is genuinely a judgement call, state the\n choice you made and, in one line, why. The human iterates on the plan by\n editing it directly, not by answering questions.\n\n On a return lap, `<%= it.vars.todoFile %>` carries the human's edits and\n inline comments on your previous plan. Fold every edit and comment into a\n revised, self-contained plan and remove the addressed comments — the plan\n is always the current, clean proposal, never a diff.\n\n Leave `<%= it.vars.todoFile %>` uncommitted and finish your turn — do\n not commit, and do not run `gtd step agent` yourself; the harness does\n that.\n on:\n \"* **\": plan-review\n\n plan-review:\n actor: human\n file: <%= it.vars.todoFile %>\n message: |\n `<%= it.vars.todoFile %>` holds the proposed implementation plan. Read it,\n then either accept it as-is or edit it — rewrite a step, add a\n constraint, or drop an inline comment — to send it back for another round.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: building\n describe: >-\n Change nothing to accept the plan as-is and move on to implementation\n (**building**).\n \"* **\":\n to: planning\n describe: >-\n Edit the plan — rewrite a step, add a constraint, or leave an inline\n comment — to send it back for another round (**planning**).\n\n building:\n actor: agent\n file: <%= it.vars.todoFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create or edit anything under `.gtd/` except deleting\n `<%= it.vars.todoFile %>`, which this prompt tells you to delete once its\n work is complete.\n\n The plan to implement is: <%~ it.read(it.vars.todoFile) %>\n\n Read that plan and implement it in full. Use TDD discipline: one test,\n then the implementation that passes it, then the next — never write all\n the tests first.\n\n Delete `<%= it.vars.todoFile %>` once the work it describes is complete\n and verified. Leave everything else uncommitted and finish your turn.\n on:\n \"* **\": checking\n\n # ── Green-baseline gate: advanced flow ────────────────────────────────────\n adv-start-check:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before starting the advanced flow; a red\n # run records .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": adv-start-blocked\n \"M .gtd/FEEDBACK.md\": adv-start-blocked\n \"D .gtd/FEEDBACK.md\": adv-grilling\n \"C\": adv-grilling\n\n adv-start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start new work on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: adv-start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**adv-start-check**). To repair the baseline\n as its own separate reviewed commit instead, abandon this start and run\n `gtd fix` from a clean `idle`.\n\n # ── Advanced flow: product + technical Q&A ────────────────────────────────\n adv-grilling:\n actor: agent\n file: <%= it.vars.requirementsFile %>\n mode: qa\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.requirementsFile %>`, which this prompt tells you to develop.\n\n `<%= it.vars.requirementsFile %>` holds the product requirements (or the\n plan you already wrote plus the human's answers on a return lap). Read it,\n explore the codebase, and develop it into a concrete, PRODUCT-level plan\n in this one turn.\n\n Scope: product and user-facing decisions only. Leave implementation\n details (file/module structure, data models, tech-stack choices) for the\n next phase (`<%= it.vars.architectureFile %>`).\n\n For every open point you cannot settle yourself, add a question under a\n `## Open Questions` heading near the top: one `### <question>` sub-heading\n each, followed by a checkbox list of candidate answers — aim for TWO\n concrete options plus a final free-text slot, ALL left UNTICKED:\n\n ### <the question>\n\n - [ ] <first option — a concrete answer, a few words of rationale>\n - [ ] <second option>\n - [ ] _your answer_\n\n Never tick a box yourself — the human ticks exactly one per question. The\n last `- [ ] _your answer_` line is the human's own-answer slot; write it\n with the literal `_your answer_` placeholder and leave it for them.\n\n On a RETURN lap the human has ticked one option per question (or replaced\n `_your answer_` with their own text). For each answered question: fold the\n chosen answer into the plan prose, then MOVE the question down into a\n `## Answered Questions` section as `### <question>` followed by the\n resolved answer in plain PROSE (drop the checkboxes). Never re-raise a\n question the human deleted; if the human deleted the whole\n `## Open Questions` section, treat the plan as accepted and surface no new\n questions unless something is genuinely still blocking. Omit\n `## Open Questions` entirely once there are none left.\n\n Leave `<%= it.vars.requirementsFile %>` uncommitted and finish your turn.\n on:\n \"* **\": adv-grilling-answer\n\n adv-grilling-answer:\n actor: human\n file: <%= it.vars.requirementsFile %>\n mode: qa\n answerGate: true\n message: |\n `<%= it.vars.requirementsFile %>` holds the product plan under\n development. Each question under `## Open Questions` offers a few options\n plus a `- [ ] _your answer_` slot. Answer EVERY question by ticking\n exactly one box (`- [x]`); for your own answer, replace `_your answer_`\n with your text and tick that line. Stepping is refused while any question\n is unanswered.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: architecting\n describe: >-\n With no open questions left (the agent surfaced none, or you deleted\n the section and it finalized the plan), change nothing to accept the\n product plan and move on to technical architecting (**architecting**).\n \"* **\":\n to: adv-grilling\n describe: >-\n Tick exactly one option per open question (replace `_your answer_` for\n your own) to send the plan back for the agent to fold your answers in\n (**adv-grilling**). Delete a question to skip it, or delete the whole\n `## Open Questions` section to accept the plan as-is.\n\n architecting:\n actor: agent\n file: <%= it.vars.architectureFile %>\n mode: qa\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.architectureFile %>` and `<%= it.vars.requirementsFile %>`,\n which this prompt tells you to write and delete respectively.\n\n Read `<%= it.vars.requirementsFile %>` (the converged product plan) and\n develop `<%= it.vars.architectureFile %>` from it in this one turn:\n file/module structure, data models, library/tech-stack choices,\n error-handling strategy — the *how*, building on the *what* already\n settled. Do not re-open product-level decisions; treat them as settled.\n\n For every open point you cannot settle yourself, add a question under a\n `## Open Questions` heading exactly as the grilling phase does: one\n `### <question>` each, followed by a checkbox list — TWO concrete options\n plus a final free-text slot, ALL left UNTICKED:\n\n ### <the question>\n\n - [ ] <first option>\n - [ ] <second option>\n - [ ] _your answer_\n\n Never tick a box yourself. On a RETURN lap the human has ticked one option\n per question (or replaced `_your answer_` with their own text): fold each\n chosen answer into the plan prose, then MOVE the question into a\n `## Answered Questions` section as `### <question>` + the resolved answer\n in plain PROSE (drop the checkboxes). Never re-raise a deleted question;\n treat a deleted `## Open Questions` section as acceptance. Omit\n `## Open Questions` once there are none left.\n\n Once `<%= it.vars.architectureFile %>` is written, delete\n `<%= it.vars.requirementsFile %>` — its content has been folded in and it\n must not linger. Leave everything uncommitted and finish your turn.\n on:\n \"* **\": architecting-answer\n\n architecting-answer:\n actor: human\n file: <%= it.vars.architectureFile %>\n mode: qa\n answerGate: true\n message: |\n `<%= it.vars.architectureFile %>` holds the technical plan under\n development. Each question under `## Open Questions` offers a few options\n plus a `- [ ] _your answer_` slot. Answer EVERY question by ticking\n exactly one box (`- [x]`); for your own answer, replace `_your answer_`\n with your text and tick that line. Stepping is refused while any question\n is unanswered.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: decompose\n describe: >-\n With no open questions left (the agent surfaced none, or you deleted\n the section and it finalized the plan), change nothing to accept the\n technical plan and move on to decomposing the work into packages\n (**decompose**).\n \"* **\":\n to: architecting\n describe: >-\n Tick exactly one option per open question (replace `_your answer_` for\n your own) to send the plan back for the agent to fold your answers in\n (**architecting**). Delete a question to skip it, or delete the whole\n `## Open Questions` section to accept the plan as-is.\n\n # ── Advanced flow: decomposition + per-package parallel build loop ─────────\n decompose:\n actor: agent\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except the\n package files this prompt tells you to write (under\n `<%= it.vars.packagesDir %>/`), and `<%= it.vars.architectureFile %>`,\n which it tells you to delete.\n\n Read `<%= it.vars.architectureFile %>` (the converged technical plan) and\n decompose it into an ordered set of WORK PACKAGES, one file each under\n `<%= it.vars.packagesDir %>/` (e.g. `<%= it.vars.packagesDir %>/01-name.md`,\n `<%= it.vars.packagesDir %>/02-name.md`, ...). Order the packages so the\n test suite can pass again after each one lands.\n\n Each package file describes a set of INDEPENDENT tasks that can be\n implemented concurrently without ordering constraints between them — a\n single build turn will fan them out to parallel subagents. Give each task\n a clear description, acceptance criteria as `- [ ]` checkboxes, and the\n relevant paths. Also state the package's overall requirement so it can be\n reviewed against its spec. Do NOT put ordering-dependent tasks in the same\n package — split them across ordered packages instead.\n\n No package file may reference any other `.gtd/` file. Once the package\n files are written, delete `<%= it.vars.architectureFile %>`. Leave\n everything uncommitted and finish your turn.\n on:\n \"* .gtd/packages/**\": picking\n\n picking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn (the package queue arbiter) — the loop driver executes\n # this verbatim, then steps the check actor. Mechanics only: take the\n # first package file (by name) under the packages dir into NEXT.md, or\n # remove NEXT.md when the queue is empty. What NEXT.md's presence/absence\n # MEANS (another package to build vs. the queue closing out to review) is\n # decided by this state's own `on` rules at capture time — never here.\n set +e\n # Hoist the NEXT path once, at the TOP: Eta's autoTrim eats the newline\n # after an interpolation tag, so no tag may be the last token on a line —\n # it would glue the next line's `else`/`fi` onto it and break the script.\n # Below this point everything is plain bash.\n nextFile=\"<%~ it.vars.nextFile %>\"\n next=$(ls <%~ it.vars.packagesDir %>/*.md 2>/dev/null | head -n 1)\n if [ -n \"$next\" ]; then\n printf '%s' \"$next\" > \"$nextFile\"\n else\n rm -f \"$nextFile\"\n fi\n on:\n \"D .gtd/NEXT.md\": reviewing\n \"* .gtd/NEXT.md\": adv-building\n \"C\": reviewing\n\n adv-building:\n actor: agent\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/`; in\n particular do NOT delete the package file (the `spec-review` gate reads it\n after you) and never touch `<%= it.vars.nextFile %>` — the `picking` state\n owns it.\n\n The package to implement is: <%~ it.read(it.vars.nextFile) %>\n\n That file describes a set of INDEPENDENT tasks. Implement ALL of them in\n this one turn, fanning the independent tasks out to parallel subagents\n where your harness supports it — each task is self-contained and can be\n built concurrently. Implement EXACTLY the tasks this package describes — no\n more, no less; leave every other package file untouched. Use TDD\n discipline within each task.\n\n Leave the package file in place and everything else uncommitted, then\n finish your turn.\n on:\n \"* **\": adv-checking\n\n adv-checking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite; a red run records .gtd/FEEDBACK.md, a\n # green run cleans it up. The `on` rules decide what that means.\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": adv-fixing\n \"M .gtd/FEEDBACK.md\": adv-fixing\n \"D .gtd/FEEDBACK.md\": spec-review\n \"C\": spec-review\n\n adv-fixing:\n actor: agent\n file: <%= it.vars.feedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n retry:\n max: 3\n otherwise: adv-escalate\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.feedbackFile %>`, which this prompt tells you to address.\n\n Read `<%= it.vars.feedbackFile %>` (the failing test output) and fix the\n code so the suite passes. Keep the change focused — do not refactor\n unrelated code. If the feedback is wrong, empty or delete\n `<%= it.vars.feedbackFile %>` instead of \"fixing\" a non-issue.\n\n Leave everything uncommitted and finish your turn — do not commit.\n on:\n \"* **\": adv-checking\n\n adv-escalate:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The agent could not get the check to pass after repeated attempts.\n `<%= it.vars.feedbackFile %>` holds the last failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: adv-checking\n describe: >-\n Fix the failure yourself — edit the code and/or\n `.gtd/FEEDBACK.md` — to re-run the check (**adv-checking**).\n\n spec-review:\n actor: agent\n model: <%= it.vars.plannerModel %>\n memory: review\n # Bounded per cycle: once entered `max` times, a transition into it is\n # redirected to `closing` (force-close the package and move on — the\n # unresolved concern is deferred to the shared human review at the tail,\n # which sees the whole diff anyway). NOTE the cap is PROCESS-scoped, so it\n # pools across packages — the same documented limitation the shared\n # `fixing` cap has (see STATES.md / docs/configuration.md).\n retry:\n max: 3\n otherwise: closing\n prompt: |\n You are an autonomous coding agent reviewing a freshly-built work package\n against its own spec. `.gtd/` holds this workflow's own state — never\n create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.specFeedbackFile %>`, which this prompt tells you to write\n when — and only when — you find problems.\n\n The package spec is: <%~ it.read(it.vars.nextFile) %>\n\n Read that spec, then verify the package's implementation (the diff below)\n against it: are all its tasks done, acceptance criteria met, and the code\n sound and consistent with the codebase?\n\n - If it fully satisfies the spec, write NOTHING and finish your turn — a\n clean turn is your approval.\n - If it does not, write `<%= it.vars.specFeedbackFile %>` listing the\n concrete problems for a fix turn to address. Be specific.\n\n Do not fix anything yourself and do not delete the package file — a later\n step owns that. Finish your turn.\n <% if (it.processDiff.trim()) { %>\n\n ## Diff under review\n\n ```diff\n <%~ it.processDiff %>\n ```\n <% } %>\n on:\n \"A .gtd/SPEC_FEEDBACK.md\": spec-fix\n \"M .gtd/SPEC_FEEDBACK.md\": spec-fix\n \"D .gtd/SPEC_FEEDBACK.md\": closing\n \"C\": closing\n\n spec-fix:\n actor: agent\n file: <%= it.vars.specFeedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.specFeedbackFile %>`, which this prompt tells you to address\n and then delete.\n\n Read `<%= it.vars.specFeedbackFile %>` (the reviewer's concerns about the\n current package) and the package spec (`<%= it.read(it.vars.nextFile) %>`),\n then fix the code to resolve every concern. Keep the change focused.\n\n Delete `<%= it.vars.specFeedbackFile %>` once every concern is addressed.\n Leave everything else uncommitted and finish your turn.\n on:\n \"* **\": adv-checking\n\n closing:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn (the package closer) — remove the just-reviewed package\n # file (its path is in NEXT.md) plus any leftover spec feedback, so\n # `picking` selects the NEXT package (or falls through to review when the\n # queue is empty). Reached on approval (spec-review clean) and on the\n # spec-review retry cap (force-close, deferring the concern to the tail).\n set +e\n pkg=$(cat <%~ it.vars.nextFile %> 2>/dev/null)\n [ -n \"$pkg\" ] && rm -f \"$pkg\"\n rm -f <%~ it.vars.specFeedbackFile %> <%~ it.vars.nextFile %>\n on:\n \"* **\": picking\n\n # ── Shared health segment (simple build, feedback loop, code-only edits) ──\n checking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite; a red run records .gtd/FEEDBACK.md, a\n # green run cleans it up. The `on` rules decide what that means.\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": fixing\n \"M .gtd/FEEDBACK.md\": fixing\n \"D .gtd/FEEDBACK.md\": reviewing\n \"C\": reviewing\n\n fixing:\n actor: agent\n file: <%= it.vars.feedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n retry:\n max: 3\n otherwise: escalate\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.feedbackFile %>`, which this prompt tells you to address.\n\n Read `<%= it.vars.feedbackFile %>` (the failing test output) and fix the\n code so the suite passes. Keep the change focused — do not refactor\n unrelated code. If the feedback is wrong, empty or delete\n `<%= it.vars.feedbackFile %>` instead of \"fixing\" a non-issue.\n\n Leave everything uncommitted and finish your turn — do not commit.\n on:\n \"* **\": checking\n\n escalate:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The agent could not get the check to pass after repeated attempts.\n `<%= it.vars.feedbackFile %>` holds the last failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: checking\n describe: >-\n Fix the failure yourself — edit the code and/or `.gtd/FEEDBACK.md` —\n to re-run the check (**checking**).\n\n # ── Green-baseline gate: `gtd review` entry ───────────────────────────────\n # `gtd review <commitish>` enters HERE (reviewEntry), not `reviewing`. It runs\n # the suite on HEAD first; green proceeds to `reviewing`, red halts. The\n # `Gtd-Review-Base:` trailer rides on this state's entry commit, so the review\n # window / incremental-diff machinery downstream is unchanged.\n review-start-check:\n actor: check\n reviewEntry: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before reviewing; a red run records\n # .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed to reviewing).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": review-start-blocked\n \"M .gtd/FEEDBACK.md\": review-start-blocked\n \"D .gtd/FEEDBACK.md\": reviewing\n \"C\": reviewing\n\n review-start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start a review on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: review-start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**review-start-check**).\n\n # ── Green-baseline gate: `gtd fix` entry ──────────────────────────────────\n # `gtd fix` enters HERE (fixEntry): run the suite, then a red run drops\n # straight into the shared `fixing` loop (-> checking -> review + squash\n # tail); a green run is a no-op back to `idle` (nothing to fix).\n fix-check:\n actor: check\n fixEntry: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite to find what needs fixing; a red run\n # records .gtd/FEEDBACK.md (-> fixing), a green run cleans it up (-> idle).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": fixing\n \"M .gtd/FEEDBACK.md\": fixing\n \"D .gtd/FEEDBACK.md\": idle\n \"C\": idle\n\n # ── Shared tail: agent review -> human review -> squash finale ────────────\n reviewing:\n actor: agent\n file: <%= it.vars.reviewFile %>\n mode: review\n model: <%= it.vars.plannerModel %>\n memory: review\n # `gtd review <commitish>` (a plain non-gtd branch, e.g. a colleague's PR)\n # does NOT enter here directly — it enters `review-start-check` (reviewEntry)\n # first, which runs the green-baseline gate and, once green, transitions\n # here. The `Gtd-Review-Base:` trailer rides on that entry commit (the\n # process's oldest), so everything below still reuses the same\n # reviewing/await-review/feedback machinery over <commitish>..HEAD.\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.reviewFile %>`, which this prompt tells you to write.\n\n Write `<%= it.vars.reviewFile %>` to help a human review the diff below in\n this EXACT format:\n\n - First non-blank line: `# Review: <%= it.currentCommit.slice(0, 7) %>`\n - Somewhere in the document: `<!-- base: <%= it.startCommit %> -->`\n - At least one `## <Chunk Title>` heading, grouping hunks semantically\n (same feature/refactor/fix, even across files) — a short explanation of\n what changed and why, then one `- [ ] ./path/to/file.ts#42 — note` file\n pointer per hunk (checkboxes are for the human to tick, not you; every\n path is `./`-relative, with an optional `#line` and an optional\n ` — note`).\n\n The diff below is `it.reviewDiff` — on a feedback round it covers ONLY the\n changes made since the previous review, so you review just what changed,\n not items already signed off. Leave `<%= it.vars.reviewFile %>`\n uncommitted and finish your turn.\n <% if (it.reviewDiff.trim()) { %>\n\n ## Full diff under review\n\n ```diff\n <%~ it.reviewDiff %>\n ```\n <% } %>\n on:\n \"* **\": await-review\n\n await-review:\n actor: human\n file: <%= it.vars.reviewFile %>\n mode: review\n # While the cycle rests here, gtd opens a \"review checkout window\": raw HEAD\n # is rewound to the review base (the most-recent `review-deciding` commit —\n # so a feedback round shows only `last-review..HEAD` — or the process start\n # on the first review) with the working tree untouched, surfacing the diff\n # as ordinary uncommitted changes. It closes on the next invocation.\n #\n # Every human step here routes to `review-deciding`, which decides sign-off\n # vs. feedback from the step's CONTENT (a comment, not a tick). Ticking a box\n # only records \"I reviewed this hunk\". Two dead ends can't be told apart by a\n # file-pattern edge, so the sign-off gate (`enforceReviewSignoffGate` in\n # src/program.ts) catches them BEFORE the step commits and refuses: an\n # unfinished review (a box still `- [ ]` with no comment) and a deleted\n # REVIEW.md.\n reviewWindow: true\n message: |\n `<%= it.vars.reviewFile %>` holds the review record for the cycle — one\n `- [ ]` checkbox per reviewable item, grouped into chunks. Tick a box\n (`- [x]`) as you review each hunk; ticking only records that you've read\n it, it is not sign-off.\n\n When you've been through the whole diff, run `gtd step human`:\n\n - Tick EVERY box and leave no comment — no note in\n `<%= it.vars.reviewFile %>`, no code edit — to sign off and collapse the\n cycle into one commit (**squashing**).\n - Leave a comment to request changes — a note on a\n `<%= it.vars.reviewFile %>` line, or a direct code edit — to send it to a\n build + re-review round (**review-deciding** → **feedback-building**). A\n code edit counts as your own fix: the agent completes the follow-through\n it implies and never reverts your lines.\n\n Stepping with a box still unticked and no comment is refused (finish\n reviewing first); so is deleting `<%= it.vars.reviewFile %>`.\n on:\n \"* **\": review-deciding\n\n review-deciding:\n actor: check\n file: <%= it.vars.reviewFile %>\n mode: review\n # Anchors the INCREMENTAL review base: its most-recent in-process commit is\n # the point the previous review round ended, so the next `reviewing` turn\n # (and the review checkout window) covers only the changes since then. On\n # the first review there is no such commit, so the base is the cycle start.\n reviewBase: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — decide the human's review step from its CONTENT. HEAD is\n # the human's `await-review -> review-deciding` commit; HEAD^ is the\n # `reviewing` commit that wrote the agent's original REVIEW.md (the sign-off\n # gate refuses an incomplete step, so review-deciding is entered exactly\n # once per round — nothing commits in between). It is FEEDBACK when the\n # human left a comment: a note in REVIEW.md (any edit beyond a \"[ ]\"->\"[x]\"\n # tick) OR a hand-edit to any non-.gtd/ file this round. Otherwise it is a\n # clean sign-off. This turn only CAPTURES the raw material into REVIEW_RAW.md\n # (the `feedback-collecting` agent then turns it into instructions); it does\n # NOT interpret it. Either way, remove REVIEW.md; what the resulting diff\n # MEANS is decided by this state's own `on` rules — the A/M REVIEW_RAW.md\n # rows are declared BEFORE the D REVIEW.md row so a feedback round (which\n # also deletes REVIEW.md) is captured as feedback, not mistaken for a\n # sign-off.\n set +e\n mkdir -p .gtd\n # Hoist the paths once, at the TOP: Eta's autoTrim eats the newline after\n # an interpolation tag, so no tag may be the last token on a line — it\n # would glue the next line onto it and break the script. Below this point\n # everything is plain bash.\n reviewFile=\"<%~ it.vars.reviewFile %>\"\n reviewRawFile=\"<%~ it.vars.reviewRawFile %>\"\n # Which non-.gtd/ files did the human hand-edit this round?\n codeFiles=$(git diff-tree --no-commit-id --name-only -r HEAD | grep -v '^\\.gtd/')\n # A note is any REVIEW.md change beyond a checkbox flip: normalize every\n # \"[ ]\"/\"[x]\" to a placeholder, then compare the agent's original (HEAD^)\n # against the human's version (HEAD).\n notes=\"\"\n before=$(git show \"HEAD^:$reviewFile\" 2>/dev/null | sed -E 's/\\[[ xX]\\]/[_]/g')\n after=$(git show \"HEAD:$reviewFile\" 2>/dev/null | sed -E 's/\\[[ xX]\\]/[_]/g')\n if [ \"$before\" != \"$after\" ]; then notes=1; fi\n if [ -n \"$codeFiles\" ] || [ -n \"$notes\" ]; then\n {\n echo \"Raw review material captured for classification. The human reviewed the diff and left the feedback below; a downstream agent turns it into an instruction list. This file is machine-captured input, not instructions.\"\n if [ -n \"$notes\" ]; then\n echo\n echo \"## Notes the human added to REVIEW.md this round\"\n echo\n echo '```diff'\n git show HEAD --format= -- \"$reviewFile\"\n echo '```'\n fi\n if [ -n \"$codeFiles\" ]; then\n echo\n echo \"## Files the human hand-edited this round (already committed)\"\n echo\n echo '```diff'\n git show HEAD --format= -- $codeFiles\n echo '```'\n fi\n } > \"$reviewRawFile\"\n fi\n rm -f \"$reviewFile\"\n on:\n \"A .gtd/REVIEW_RAW.md\": feedback-collecting\n \"M .gtd/REVIEW_RAW.md\": feedback-collecting\n \"D .gtd/REVIEW.md\": squashing\n\n feedback-collecting:\n actor: agent\n file: <%= it.vars.reviewFeedbackFile %>\n model: <%= it.vars.plannerModel %>\n memory: review\n prompt: |\n You are an autonomous coding agent turning raw review feedback into an\n explicit instruction list for a builder. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.reviewRawFile %>` (delete it when done) and\n `<%= it.vars.reviewFeedbackFile %>` (write it). Do NOT change any other\n file — you classify, you do not build.\n\n The raw review material is: <%~ it.read(it.vars.reviewRawFile) %>\n\n Classify every piece of it into `<%= it.vars.reviewFeedbackFile %>` as a\n flat, numbered instruction list. Each item is `N. ./path/to/file.ts#line —\n <imperative>`. Read the two RAW sections and apply these rules exactly:\n\n 1. NOTES the human added to REVIEW.md — each note is a MANDATORY change,\n regardless of whether its checkbox is ticked (ticking means only \"I read\n this hunk\", never sign-off). Anchor each to the `./path#line` its review\n item names (or the chunk it sits under). Emit it as a concrete\n imperative.\n 2. Every COMMENT the human ADDED this round (a `+` line that is a code\n comment, in the hand-edited files) is a MANDATORY instruction the human\n is giving the builder — even a plain-prose one, even if its box is\n ticked. Emit an imperative to satisfy it and note that the comment line\n itself must be REMOVED once addressed. If a comment turns out to describe\n behaviour the code already has, the instruction is still \"confirm the\n code matches and remove the comment line\".\n 3. Every NON-comment code line the human hand-edited is an already-committed\n INTENT, NOT a do-then-delete item. Emit an instruction that names those\n files and says: their lines are final — complete ONLY the follow-through\n they imply (callers, tests, types, docs) and NEVER revert or rewrite\n them. Do not turn their own edit into a task.\n\n Split each hand-edited hunk per line: comment `+` lines follow rule 2, the\n surrounding real code follows rule 3.\n\n If — and only if — nothing in the raw material is actionable (e.g. the human\n left only an approving remark), write `<%= it.vars.reviewFeedbackFile %>`\n containing exactly one line: `NOTHING ACTIONABLE — <one-sentence reason>`.\n Never invent work to satisfy a non-actionable remark.\n\n Delete `<%= it.vars.reviewRawFile %>`, leave everything else uncommitted,\n and finish your turn.\n on:\n \"A .gtd/REVIEW_FEEDBACK.md\": feedback-building\n \"M .gtd/REVIEW_FEEDBACK.md\": feedback-building\n\n feedback-building:\n actor: agent\n file: <%= it.vars.reviewFeedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n # Refuse a work-free turn: a step whose only pending change is deleting the\n # instructions file (the original \"captured then discarded\" bug). The edge\n # gate (`enforceFeedbackProgressGate` in src/program.ts) reads this flag and\n # exempts a `NOTHING ACTIONABLE` sentinel (a non-actionable review round,\n # which legitimately makes no code change). The pure engine carries it inert.\n requireProgress: true\n prompt: |\n You are an autonomous coding agent addressing review feedback. `.gtd/`\n holds this workflow's own state — never create, edit, or delete anything\n under `.gtd/` except `<%= it.vars.reviewFeedbackFile %>`, which this\n prompt tells you to address and then delete.\n\n The instructions to implement are: <%~ it.read(it.vars.reviewFeedbackFile) %>\n\n This is a flat instruction list, not a diff — execute every item exactly as\n written, no Q&A, no re-planning, using TDD discipline:\n\n - An item that says the human's own lines are final: build ON TOP of them to\n complete only the follow-through it names (callers, tests, types, docs).\n NEVER revert or rewrite the lines they already committed.\n - An item derived from a human comment: satisfy it AND delete that comment\n line from the code (the human's review comments are transient — none of\n them survive this round).\n\n If the file's sole content is a `NOTHING ACTIONABLE` line, make no code\n change; just delete the instructions file.\n\n Delete `<%= it.vars.reviewFeedbackFile %>` once every item is addressed.\n Leave everything else uncommitted and finish your turn. Deleting the\n instructions file WITHOUT making the changes it asks for is refused — the\n feedback must actually be addressed.\n on:\n \"* **\": checking\n\n squashing:\n actor: agent\n file: <%= it.vars.commitMsgFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. The cycle is approved and done.\n `.gtd/` holds this workflow's own state — never create, edit, or delete\n anything under `.gtd/` except `<%= it.vars.commitMsgFile %>`, which this\n prompt tells you to write.\n\n Leave `<%= it.vars.commitMsgFile %>` uncommitted and finish your turn —\n entering this file squashes everything this process retains into one\n commit using its content as the message. The diff below is exactly what\n that commit will contain: `it.retainedDiff`, the changes THIS process\n made (its trace/retry boundary onward). For a normal build cycle that is\n the whole feature; for a `gtd review` process it is only the fixes made\n during the review — NOT the changeset that was under review.\n <% if (it.retainedDiff.trim()) { %>\n\n Write `<%= it.vars.commitMsgFile %>` with ONE conventional-commits message\n for the changes below (subject line `type(scope): subject`, imperative\n mood, <= 72 characters; a body explaining the why, trade-offs, and key\n decisions). Plain text, no markdown wrapper.\n\n ## Retained diff\n\n ```diff\n <%~ it.retainedDiff %>\n ```\n <% } else { %>\n\n This process retained NO changes (a clean review sign-off with no fixes).\n Write `<%= it.vars.commitMsgFile %>` with exactly this one line and\n nothing else:\n\n chore: human review\n <% } %>\n on:\n \"A .gtd/COMMIT_MSG.md\": done\n \"M .gtd/COMMIT_MSG.md\": done\n\n done:\n commit: |\n <%~ it.read(it.vars.commitMsgFile) %>\n\n Token cost: <%= it.processCost %>\n <% it.processCostByModel.forEach(function(m){ %>\n - <%= m.model %>: <%= m.cost %>\n <% }) %>\n";
|
|
190190
|
+
//#endregion
|
|
190191
|
+
//#region src/workflows/templates.ts
|
|
190192
|
+
/**
|
|
190193
|
+
* The `$schema` URL editors resolve for `.gtdrc.json` completion/validation —
|
|
190194
|
+
* written as the first key of every `gtd init` config (see `renderInitScaffold`).
|
|
190195
|
+
*/
|
|
190196
|
+
const SCHEMA_URL = "https://raw.githubusercontent.com/pmelab/gtd/main/schema.json";
|
|
190197
|
+
/**
|
|
190198
|
+
* The default `vars:` `gtd init` seeds into the scaffolded `.gtdrc.json` — the
|
|
190199
|
+
* one variable a fresh project almost always changes. It mirrors the bundled
|
|
190200
|
+
* workflow's OWN `testCommand` default (`npm test`), surfaced at the top level
|
|
190201
|
+
* as a ready-to-edit override (the top-level `vars:` layer wins over the
|
|
190202
|
+
* workflow's own — see `src/Edge.ts`'s `resolveVars`). Everything else the
|
|
190203
|
+
* workflow needs already ships inside the built-in default, so there is nothing
|
|
190204
|
+
* else to seed.
|
|
190205
|
+
*/
|
|
190206
|
+
const INIT_VARS = { testCommand: "npm test" };
|
|
190207
|
+
/**
|
|
190208
|
+
* The top-level `modes:` block `gtd init` seeds into the scaffolded
|
|
190209
|
+
* `.gtdrc.json` as a ready-to-edit suggestion: a `format:` command for each
|
|
190210
|
+
* built-in steering-file mode the bundled default uses (`qa` for the plan /
|
|
190211
|
+
* open-questions files, `review` for REVIEW.md), so a fresh project's steering
|
|
190212
|
+
* files are auto-formatted with Prettier before gtd validates them. Only
|
|
190213
|
+
* `format:` is declared — gtd's built-in `qa`/`review` validators still do the
|
|
190214
|
+
* validating (the two halves layer independently — see STATES.md §12 /
|
|
190215
|
+
* docs/configuration.md `modes:`). gtd ships no formatter, so this is the one
|
|
190216
|
+
* place a default is suggested; a project edits or drops it freely (swap
|
|
190217
|
+
* Prettier for dprint, point at a script, delete the key).
|
|
190218
|
+
*/
|
|
190219
|
+
const MODES_SUGGESTION = {
|
|
190220
|
+
qa: { format: "npx prettier --write <%= it.file %>" },
|
|
190221
|
+
review: { format: "npx prettier --write <%= it.file %>" }
|
|
190222
|
+
};
|
|
190223
|
+
/**
|
|
190224
|
+
* The single bundled workflow template — the raw YAML text of `unified.yaml`,
|
|
190225
|
+
* imported as a string (tsdown's `.yaml` text loader / the vitest `rawMd`
|
|
190226
|
+
* transform — see tsdown.config.ts / tests/vitest.rawMd.ts), so this module
|
|
190227
|
+
* never touches the filesystem: it works identically in the dev checkout,
|
|
190228
|
+
* under `vitest`, and inside the single-file `dist/gtd.bundle.mjs` build. gtd
|
|
190229
|
+
* ships this as its BUILT-IN DEFAULT — a repo with no `workflow:` configured
|
|
190230
|
+
* runs it directly (see `src/Config.ts`'s `toOperations`), so `gtd init` no
|
|
190231
|
+
* longer writes the workflow into the config at all.
|
|
190232
|
+
*/
|
|
190233
|
+
const UNIFIED_WORKFLOW = unified_default;
|
|
190234
|
+
/**
|
|
190235
|
+
* The bundled default, compiled once through the exact same
|
|
190236
|
+
* `compileWorkflowConfig` a user's `.gtdrc` `workflow:` key goes through — no
|
|
190237
|
+
* privileged code path. `src/Config.ts` (and the in-memory test layer) fall
|
|
190238
|
+
* back to this whenever no `workflow:` key is configured; `compileTemplate`
|
|
190239
|
+
* exposes it fresh for Mermaid rendering and tests. `configDir` is `"."` and
|
|
190240
|
+
* never consulted: no template content value starts with `./`/`../`.
|
|
190241
|
+
*/
|
|
190242
|
+
const DEFAULT_WORKFLOW = compileWorkflowConfig((0, import_dist$1.parse)(UNIFIED_WORKFLOW), ".");
|
|
190243
|
+
/** The compiled built-in default workflow definition — the fallback when no `workflow:` is configured. */
|
|
190244
|
+
const defaultWorkflowDefinition = DEFAULT_WORKFLOW.definition;
|
|
190245
|
+
/** The built-in default workflow's own declared `vars:` defaults (layer 1 of the merged `it.vars`). */
|
|
190246
|
+
const defaultWorkflowVars = DEFAULT_WORKFLOW.vars;
|
|
190247
|
+
/**
|
|
190248
|
+
* Render what `gtd init` writes: a minimal `.gtdrc.json` seeding the default
|
|
190249
|
+
* variables (`vars.testCommand`) and a ready-to-edit Prettier formatting
|
|
190250
|
+
* suggestion (`modes:`). It carries NO `workflow:` key — gtd ships the unified
|
|
190251
|
+
* workflow as its built-in default and runs it whenever none is configured
|
|
190252
|
+
* (see `src/Config.ts`). A project that wants to customize the machine itself
|
|
190253
|
+
* adds a `workflow:` key (materialize the default with `renderInitConfig` as a
|
|
190254
|
+
* starting point); everyday tuning is just editing the seeded `vars:`/`modes:`.
|
|
190255
|
+
*/
|
|
190256
|
+
const renderInitScaffold = () => {
|
|
190257
|
+
return { config: JSON.stringify({
|
|
190258
|
+
$schema: SCHEMA_URL,
|
|
190259
|
+
vars: INIT_VARS,
|
|
190260
|
+
modes: MODES_SUGGESTION
|
|
190261
|
+
}, null, 2) + "\n" };
|
|
190262
|
+
};
|
|
190263
|
+
//#endregion
|
|
190188
190264
|
//#region src/Cwd.ts
|
|
190189
190265
|
var Cwd = class Cwd extends Tag("Cwd")() {
|
|
190190
190266
|
static layer = (root) => succeed$2(Cwd, { root });
|
|
@@ -190558,26 +190634,34 @@ const compileRcVars = (raw) => {
|
|
|
190558
190634
|
return vars;
|
|
190559
190635
|
};
|
|
190560
190636
|
/**
|
|
190561
|
-
*
|
|
190562
|
-
*
|
|
190563
|
-
*
|
|
190564
|
-
*
|
|
190565
|
-
|
|
190566
|
-
|
|
190567
|
-
|
|
190568
|
-
*
|
|
190569
|
-
*
|
|
190570
|
-
*
|
|
190571
|
-
*
|
|
190572
|
-
*
|
|
190573
|
-
*
|
|
190574
|
-
* `gtd init`), or (via `compileWorkflowConfig`/`compileRcVars`) on any invalid
|
|
190575
|
-
* workflow/vars.
|
|
190637
|
+
* Compile the decoded config's `workflow:` key (or gtd's built-in bundled
|
|
190638
|
+
* default, when absent) plus its top-level `vars:`/`modes:` keys into
|
|
190639
|
+
* `ConfigOperations`. A custom `workflow:`'s `./`/`../` content file references
|
|
190640
|
+
* were already inlined per declaring file by `loadMerged`, so the compiler is
|
|
190641
|
+
* invoked with `inlineFileRefs: false` and `root` is passed only as an (unused)
|
|
190642
|
+
* `configDir` placeholder.
|
|
190643
|
+
*
|
|
190644
|
+
* When no `workflow:` key is configured anywhere in the cwd→home chain, the
|
|
190645
|
+
* built-in default (`defaultWorkflowDefinition`, pre-compiled and validated
|
|
190646
|
+
* once at module load) is used. Layering the top-level `modes:` over it can
|
|
190647
|
+
* only ADD mode names (never invalidate a `mode:` reference), so it needs no
|
|
190648
|
+
* re-validation. Throws (via `compileWorkflowConfig`/`compileRcVars`) only on
|
|
190649
|
+
* an invalid CUSTOM workflow/vars; the built-in default never throws here.
|
|
190576
190650
|
*/
|
|
190577
190651
|
const toOperations = (decoded, root) => {
|
|
190578
190652
|
const rcVars = compileRcVars(decoded.vars);
|
|
190579
190653
|
const rcModes = compileRcModes(decoded.modes);
|
|
190580
|
-
if (decoded.workflow === void 0)
|
|
190654
|
+
if (decoded.workflow === void 0) {
|
|
190655
|
+
const modes = mergeModes(defaultWorkflowDefinition.modes, rcModes);
|
|
190656
|
+
return {
|
|
190657
|
+
workflow: modes !== void 0 ? {
|
|
190658
|
+
...defaultWorkflowDefinition,
|
|
190659
|
+
modes
|
|
190660
|
+
} : defaultWorkflowDefinition,
|
|
190661
|
+
workflowVars: defaultWorkflowVars,
|
|
190662
|
+
rcVars
|
|
190663
|
+
};
|
|
190664
|
+
}
|
|
190581
190665
|
const { definition, vars: workflowVars } = compileWorkflowConfig(decoded.workflow, root, rcModes, false);
|
|
190582
190666
|
return {
|
|
190583
190667
|
workflow: definition,
|
|
@@ -191557,96 +191641,6 @@ var WorktreeReader = class WorktreeReader extends Tag("WorktreeReader")() {
|
|
|
191557
191641
|
}));
|
|
191558
191642
|
};
|
|
191559
191643
|
//#endregion
|
|
191560
|
-
//#region src/workflows/unified.yaml
|
|
191561
|
-
var unified_default = "# The unified gtd workflow template — written verbatim into `.gtdrc.json`\n# (nested under a `workflow:` key) by `gtd init` (no argument). gtd ships no\n# default workflow: a repo picks this bundled template with `gtd init`, and a\n# state command run with no workflow configured fails (see src/Config.ts).\n# See STATES.md §10 for the full walkthrough.\n#\n# Compiled through the exact same `compileWorkflowConfig` a user's `.gtdrc`\n# `workflow:` key goes through — no privileged code path\n# (src/workflows/templates.ts does the compiling). Every content string below\n# is INLINE (no `./`-relative file references): the bundled template ships\n# inside a single-file build (`dist/gtd.bundle.mjs`), so its content must\n# already be resolved at BUILD time. `gtd init` DERIVES the scaffolded\n# `.gtdrc.json` from this inline source (`renderInitScaffold`): each agent\n# state's `prompt:` is written out as an editable `gtd-prompts/<state>.md`\n# file; human `message:`/check `script:`/the `done` `commit:` body stay inline.\n#\n# ── Four entry points behind a green-baseline gate, one shared tail ─────────\n#\n# EVERY entry first runs the test suite and only proceeds when it is GREEN — you\n# never start new work (or a review) on top of a red baseline. A red run halts\n# at a human `*-start-blocked` gate (fix the failures and re-run, exactly like\n# the `escalate` states), or is what `gtd fix` exists to repair.\n#\n# The initial `idle` state FORKS on which steering file the human creates,\n# routing into that flow's OWN start gate:\n#\n# * .gtd/REQUIREMENTS.md -> `adv-start-check` -> the ADVANCED flow (product +\n# technical Q&A, package decomposition, per-package parallel build +\n# agentic spec-review).\n# * anything else (e.g. .gtd/TODO.md) -> `start-check` -> the SIMPLE flow (one\n# grilling Q&A loop, a monolithic build, no decomposition, no agentic\n# review).\n#\n# A third entry, `gtd review <commitish>`, jumps to `review-start-check`\n# (reviewEntry) and, once green, to `reviewing` to review a foreign branch\n# through the same shared tail. A fourth, `gtd fix`, jumps to `fix-check`\n# (fixEntry): a red suite drops straight into the shared `fixing` loop and out\n# through the review + squash tail; a green suite is a no-op back to `idle`.\n#\n# All three converge at `reviewing` -> `await-review`. Ticking a REVIEW.md box\n# means only \"I reviewed this hunk\"; a COMMENT (not an unticked box) is what asks\n# for changes. Every human step at `await-review` goes to `review-deciding`,\n# which inspects the step and routes:\n# * no comment (every box ticked, no REVIEW.md note, no code edit) -> the diff\n# is a bare REVIEW.md deletion -> squashing -> done (the ONLY path to the\n# finale — the whole cycle collapses into one commit).\n# * any comment — a note in REVIEW.md OR a hand-edit to code — ->\n# review-deciding writes REVIEW_FEEDBACK.md -> feedback-building implements\n# it (completing any code the human hand-edited, never reverting their\n# lines) -> checking -> reviewing regenerates an INCREMENTAL REVIEW.md\n# (review-deciding carries `reviewBase: true`, so each feedback round's\n# review + checkout window covers only `last-review..HEAD`, i.e. the agent's\n# follow-through, not the human's own edit) -> await-review, looping until\n# sign-off.\n# Two dead ends never commit: the sign-off gate (src/program.ts) REFUSES a step\n# that leaves a box unticked with no comment (finish reviewing first) and a\n# deleted REVIEW.md (restore it and tick the boxes).\n#\n# The shared health segment (`checking`/`fixing`/`escalate`) serves the simple\n# build and the feedback loop — its green edge targets\n# `reviewing`. The advanced per-package loop keeps its OWN health triple\n# (`adv-checking`/`adv-fixing`/`adv-escalate`) because its green edge targets\n# the per-package `spec-review` gate instead.\n#\n# KNOWN LIMITATION: `on` pattern keys are NOT Eta templates — they keep the\n# LITERAL `.gtd/...` paths matching these vars' DEFAULT values. Repointing a\n# file var changes what templates read/write WITHOUT changing what the `on`\n# patterns match, desyncing the machine (see docs/configuration.md).\n\nvars:\n testCommand: npm test\n todoFile: .gtd/TODO.md\n requirementsFile: .gtd/REQUIREMENTS.md\n architectureFile: .gtd/ARCHITECTURE.md\n packagesDir: .gtd/packages\n nextFile: .gtd/NEXT.md\n reviewFile: .gtd/REVIEW.md\n reviewRawFile: .gtd/REVIEW_RAW.md\n reviewFeedbackFile: .gtd/REVIEW_FEEDBACK.md\n feedbackFile: .gtd/FEEDBACK.md\n specFeedbackFile: .gtd/SPEC_FEEDBACK.md\n commitMsgFile: .gtd/COMMIT_MSG.md\n # The two opaque model tiers every agent state draws from — repoint them here\n # (or via a top-level `.gtdrc` `vars:` key / a `GTD_VAR_plannerModel` env var)\n # to change every state on that tier at once. `plannerModel` (default \"smart\")\n # is the heavier tier for the one-shot planning/architecting/review turns;\n # `coderModel` (default \"base\") is the tier for the build/fix turns.\n plannerModel: smart\n coderModel: base\n\nstates:\n # ── Shared entry ────────────────────────────────────────────────────────\n idle:\n actor: human\n initial: true\n # Every human-gate `message:` below closes with the same rendered \"What\n # each change does next\" list, built from `it.edges` (the resting state's\n # own `on` edges — each edge's `describe:` is the single source of truth).\n message: |\n No active gtd cycle.\n\n To start one, create a steering file describing what you want built:\n\n - `.gtd/TODO.md` — a short sketch — starts the SIMPLE flow (plan, build,\n review).\n - `.gtd/REQUIREMENTS.md` — the product requirements — starts the ADVANCED\n flow (product + technical Q&A, package decomposition, parallel build,\n per-package agentic review).\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* .gtd/REQUIREMENTS.md\":\n to: adv-start-check\n describe: >-\n Save the product requirements to `.gtd/REQUIREMENTS.md` to start the\n ADVANCED flow — gtd first checks the test baseline is green, then the\n agent develops them through product then technical Q&A, decomposes the\n work into packages, and builds each in parallel (**adv-start-check**).\n \"* **\":\n to: start-check\n describe: >-\n Save a short sketch to `.gtd/TODO.md` (or any other change) to start\n the SIMPLE flow — gtd first checks the test baseline is green, then the\n agent reads it, explores the codebase, and develops it into a concrete\n implementation plan (**start-check**).\n\n # ── Green-baseline gate: simple flow ──────────────────────────────────────\n # Runs the suite before any planning starts. Its script is `checking`'s test\n # wrapper verbatim (red -> .gtd/FEEDBACK.md, green -> remove it); the `on`\n # rules turn that into \"halt at start-blocked\" vs \"proceed to planning\".\n start-check:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before starting new work; a red run\n # records .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": start-blocked\n \"M .gtd/FEEDBACK.md\": start-blocked\n \"D .gtd/FEEDBACK.md\": planning\n \"C\": planning\n\n start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start new work on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**start-check**). To repair the baseline as\n its own separate reviewed commit instead, abandon this start and run\n `gtd fix` from a clean `idle`.\n\n # ── Simple flow: plan-iteration loop, monolithic build ────────────────────\n planning:\n actor: agent\n file: <%= it.vars.todoFile %>\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.todoFile %>`, which this prompt tells you to develop.\n\n `<%= it.vars.todoFile %>` holds a short sketch of what to build — or, on a\n return lap, the plan you already wrote plus the human's edits and comments\n on it. Read it, explore the codebase, and develop it into a concrete\n implementation plan: the files to change, the approach, and the steps to\n take.\n\n Do NOT ask questions and do NOT add an \"Open Questions\" section — decide\n every open point yourself and write the plan as a set of concrete\n decisions. Where a decision is genuinely a judgement call, state the\n choice you made and, in one line, why. The human iterates on the plan by\n editing it directly, not by answering questions.\n\n On a return lap, `<%= it.vars.todoFile %>` carries the human's edits and\n inline comments on your previous plan. Fold every edit and comment into a\n revised, self-contained plan and remove the addressed comments — the plan\n is always the current, clean proposal, never a diff.\n\n Leave `<%= it.vars.todoFile %>` uncommitted and finish your turn — do\n not commit, and do not run `gtd step agent` yourself; the harness does\n that.\n on:\n \"* **\": plan-review\n\n plan-review:\n actor: human\n file: <%= it.vars.todoFile %>\n message: |\n `<%= it.vars.todoFile %>` holds the proposed implementation plan. Read it,\n then either accept it as-is or edit it — rewrite a step, add a\n constraint, or drop an inline comment — to send it back for another round.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: building\n describe: >-\n Change nothing to accept the plan as-is and move on to implementation\n (**building**).\n \"* **\":\n to: planning\n describe: >-\n Edit the plan — rewrite a step, add a constraint, or leave an inline\n comment — to send it back for another round (**planning**).\n\n building:\n actor: agent\n file: <%= it.vars.todoFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create or edit anything under `.gtd/` except deleting\n `<%= it.vars.todoFile %>`, which this prompt tells you to delete once its\n work is complete.\n\n The plan to implement is: <%~ it.read(it.vars.todoFile) %>\n\n Read that plan and implement it in full. Use TDD discipline: one test,\n then the implementation that passes it, then the next — never write all\n the tests first.\n\n Delete `<%= it.vars.todoFile %>` once the work it describes is complete\n and verified. Leave everything else uncommitted and finish your turn.\n on:\n \"* **\": checking\n\n # ── Green-baseline gate: advanced flow ────────────────────────────────────\n adv-start-check:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before starting the advanced flow; a red\n # run records .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": adv-start-blocked\n \"M .gtd/FEEDBACK.md\": adv-start-blocked\n \"D .gtd/FEEDBACK.md\": adv-grilling\n \"C\": adv-grilling\n\n adv-start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start new work on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: adv-start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**adv-start-check**). To repair the baseline\n as its own separate reviewed commit instead, abandon this start and run\n `gtd fix` from a clean `idle`.\n\n # ── Advanced flow: product + technical Q&A ────────────────────────────────\n adv-grilling:\n actor: agent\n file: <%= it.vars.requirementsFile %>\n mode: qa\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.requirementsFile %>`, which this prompt tells you to develop.\n\n `<%= it.vars.requirementsFile %>` holds the product requirements (or the\n plan you already wrote plus the human's answers on a return lap). Read it,\n explore the codebase, and develop it into a concrete, PRODUCT-level plan\n in this one turn.\n\n Scope: product and user-facing decisions only. Leave implementation\n details (file/module structure, data models, tech-stack choices) for the\n next phase (`<%= it.vars.architectureFile %>`).\n\n For every open point you cannot settle yourself, add a question under a\n `## Open Questions` heading near the top: one `### <question>` sub-heading\n each, followed by a checkbox list of candidate answers — aim for TWO\n concrete options plus a final free-text slot, ALL left UNTICKED:\n\n ### <the question>\n\n - [ ] <first option — a concrete answer, a few words of rationale>\n - [ ] <second option>\n - [ ] _your answer_\n\n Never tick a box yourself — the human ticks exactly one per question. The\n last `- [ ] _your answer_` line is the human's own-answer slot; write it\n with the literal `_your answer_` placeholder and leave it for them.\n\n On a RETURN lap the human has ticked one option per question (or replaced\n `_your answer_` with their own text). For each answered question: fold the\n chosen answer into the plan prose, then MOVE the question down into a\n `## Answered Questions` section as `### <question>` followed by the\n resolved answer in plain PROSE (drop the checkboxes). Never re-raise a\n question the human deleted; if the human deleted the whole\n `## Open Questions` section, treat the plan as accepted and surface no new\n questions unless something is genuinely still blocking. Omit\n `## Open Questions` entirely once there are none left.\n\n Leave `<%= it.vars.requirementsFile %>` uncommitted and finish your turn.\n on:\n \"* **\": adv-grilling-answer\n\n adv-grilling-answer:\n actor: human\n file: <%= it.vars.requirementsFile %>\n mode: qa\n answerGate: true\n message: |\n `<%= it.vars.requirementsFile %>` holds the product plan under\n development. Each question under `## Open Questions` offers a few options\n plus a `- [ ] _your answer_` slot. Answer EVERY question by ticking\n exactly one box (`- [x]`); for your own answer, replace `_your answer_`\n with your text and tick that line. Stepping is refused while any question\n is unanswered.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: architecting\n describe: >-\n With no open questions left (the agent surfaced none, or you deleted\n the section and it finalized the plan), change nothing to accept the\n product plan and move on to technical architecting (**architecting**).\n \"* **\":\n to: adv-grilling\n describe: >-\n Tick exactly one option per open question (replace `_your answer_` for\n your own) to send the plan back for the agent to fold your answers in\n (**adv-grilling**). Delete a question to skip it, or delete the whole\n `## Open Questions` section to accept the plan as-is.\n\n architecting:\n actor: agent\n file: <%= it.vars.architectureFile %>\n mode: qa\n model: <%= it.vars.plannerModel %>\n memory: plan\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.architectureFile %>` and `<%= it.vars.requirementsFile %>`,\n which this prompt tells you to write and delete respectively.\n\n Read `<%= it.vars.requirementsFile %>` (the converged product plan) and\n develop `<%= it.vars.architectureFile %>` from it in this one turn:\n file/module structure, data models, library/tech-stack choices,\n error-handling strategy — the *how*, building on the *what* already\n settled. Do not re-open product-level decisions; treat them as settled.\n\n For every open point you cannot settle yourself, add a question under a\n `## Open Questions` heading exactly as the grilling phase does: one\n `### <question>` each, followed by a checkbox list — TWO concrete options\n plus a final free-text slot, ALL left UNTICKED:\n\n ### <the question>\n\n - [ ] <first option>\n - [ ] <second option>\n - [ ] _your answer_\n\n Never tick a box yourself. On a RETURN lap the human has ticked one option\n per question (or replaced `_your answer_` with their own text): fold each\n chosen answer into the plan prose, then MOVE the question into a\n `## Answered Questions` section as `### <question>` + the resolved answer\n in plain PROSE (drop the checkboxes). Never re-raise a deleted question;\n treat a deleted `## Open Questions` section as acceptance. Omit\n `## Open Questions` once there are none left.\n\n Once `<%= it.vars.architectureFile %>` is written, delete\n `<%= it.vars.requirementsFile %>` — its content has been folded in and it\n must not linger. Leave everything uncommitted and finish your turn.\n on:\n \"* **\": architecting-answer\n\n architecting-answer:\n actor: human\n file: <%= it.vars.architectureFile %>\n mode: qa\n answerGate: true\n message: |\n `<%= it.vars.architectureFile %>` holds the technical plan under\n development. Each question under `## Open Questions` offers a few options\n plus a `- [ ] _your answer_` slot. Answer EVERY question by ticking\n exactly one box (`- [x]`); for your own answer, replace `_your answer_`\n with your text and tick that line. Stepping is refused while any question\n is unanswered.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"C\":\n to: decompose\n describe: >-\n With no open questions left (the agent surfaced none, or you deleted\n the section and it finalized the plan), change nothing to accept the\n technical plan and move on to decomposing the work into packages\n (**decompose**).\n \"* **\":\n to: architecting\n describe: >-\n Tick exactly one option per open question (replace `_your answer_` for\n your own) to send the plan back for the agent to fold your answers in\n (**architecting**). Delete a question to skip it, or delete the whole\n `## Open Questions` section to accept the plan as-is.\n\n # ── Advanced flow: decomposition + per-package parallel build loop ─────────\n decompose:\n actor: agent\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except the\n package files this prompt tells you to write (under\n `<%= it.vars.packagesDir %>/`), and `<%= it.vars.architectureFile %>`,\n which it tells you to delete.\n\n Read `<%= it.vars.architectureFile %>` (the converged technical plan) and\n decompose it into an ordered set of WORK PACKAGES, one file each under\n `<%= it.vars.packagesDir %>/` (e.g. `<%= it.vars.packagesDir %>/01-name.md`,\n `<%= it.vars.packagesDir %>/02-name.md`, ...). Order the packages so the\n test suite can pass again after each one lands.\n\n Each package file describes a set of INDEPENDENT tasks that can be\n implemented concurrently without ordering constraints between them — a\n single build turn will fan them out to parallel subagents. Give each task\n a clear description, acceptance criteria as `- [ ]` checkboxes, and the\n relevant paths. Also state the package's overall requirement so it can be\n reviewed against its spec. Do NOT put ordering-dependent tasks in the same\n package — split them across ordered packages instead.\n\n No package file may reference any other `.gtd/` file. Once the package\n files are written, delete `<%= it.vars.architectureFile %>`. Leave\n everything uncommitted and finish your turn.\n on:\n \"* .gtd/packages/**\": picking\n\n picking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn (the package queue arbiter) — the loop driver executes\n # this verbatim, then steps the check actor. Mechanics only: take the\n # first package file (by name) under the packages dir into NEXT.md, or\n # remove NEXT.md when the queue is empty. What NEXT.md's presence/absence\n # MEANS (another package to build vs. the queue closing out to review) is\n # decided by this state's own `on` rules at capture time — never here.\n set +e\n # Hoist the NEXT path once, at the TOP: Eta's autoTrim eats the newline\n # after an interpolation tag, so no tag may be the last token on a line —\n # it would glue the next line's `else`/`fi` onto it and break the script.\n # Below this point everything is plain bash.\n nextFile=\"<%~ it.vars.nextFile %>\"\n next=$(ls <%~ it.vars.packagesDir %>/*.md 2>/dev/null | head -n 1)\n if [ -n \"$next\" ]; then\n printf '%s' \"$next\" > \"$nextFile\"\n else\n rm -f \"$nextFile\"\n fi\n on:\n \"D .gtd/NEXT.md\": reviewing\n \"* .gtd/NEXT.md\": adv-building\n \"C\": reviewing\n\n adv-building:\n actor: agent\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/`; in\n particular do NOT delete the package file (the `spec-review` gate reads it\n after you) and never touch `<%= it.vars.nextFile %>` — the `picking` state\n owns it.\n\n The package to implement is: <%~ it.read(it.vars.nextFile) %>\n\n That file describes a set of INDEPENDENT tasks. Implement ALL of them in\n this one turn, fanning the independent tasks out to parallel subagents\n where your harness supports it — each task is self-contained and can be\n built concurrently. Implement EXACTLY the tasks this package describes — no\n more, no less; leave every other package file untouched. Use TDD\n discipline within each task.\n\n Leave the package file in place and everything else uncommitted, then\n finish your turn.\n on:\n \"* **\": adv-checking\n\n adv-checking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite; a red run records .gtd/FEEDBACK.md, a\n # green run cleans it up. The `on` rules decide what that means.\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": adv-fixing\n \"M .gtd/FEEDBACK.md\": adv-fixing\n \"D .gtd/FEEDBACK.md\": spec-review\n \"C\": spec-review\n\n adv-fixing:\n actor: agent\n file: <%= it.vars.feedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n retry:\n max: 3\n otherwise: adv-escalate\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.feedbackFile %>`, which this prompt tells you to address.\n\n Read `<%= it.vars.feedbackFile %>` (the failing test output) and fix the\n code so the suite passes. Keep the change focused — do not refactor\n unrelated code. If the feedback is wrong, empty or delete\n `<%= it.vars.feedbackFile %>` instead of \"fixing\" a non-issue.\n\n Leave everything uncommitted and finish your turn — do not commit.\n on:\n \"* **\": adv-checking\n\n adv-escalate:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The agent could not get the check to pass after repeated attempts.\n `<%= it.vars.feedbackFile %>` holds the last failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: adv-checking\n describe: >-\n Fix the failure yourself — edit the code and/or\n `.gtd/FEEDBACK.md` — to re-run the check (**adv-checking**).\n\n spec-review:\n actor: agent\n model: <%= it.vars.plannerModel %>\n memory: review\n # Bounded per cycle: once entered `max` times, a transition into it is\n # redirected to `closing` (force-close the package and move on — the\n # unresolved concern is deferred to the shared human review at the tail,\n # which sees the whole diff anyway). NOTE the cap is PROCESS-scoped, so it\n # pools across packages — the same documented limitation the shared\n # `fixing` cap has (see STATES.md / docs/configuration.md).\n retry:\n max: 3\n otherwise: closing\n prompt: |\n You are an autonomous coding agent reviewing a freshly-built work package\n against its own spec. `.gtd/` holds this workflow's own state — never\n create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.specFeedbackFile %>`, which this prompt tells you to write\n when — and only when — you find problems.\n\n The package spec is: <%~ it.read(it.vars.nextFile) %>\n\n Read that spec, then verify the package's implementation (the diff below)\n against it: are all its tasks done, acceptance criteria met, and the code\n sound and consistent with the codebase?\n\n - If it fully satisfies the spec, write NOTHING and finish your turn — a\n clean turn is your approval.\n - If it does not, write `<%= it.vars.specFeedbackFile %>` listing the\n concrete problems for a fix turn to address. Be specific.\n\n Do not fix anything yourself and do not delete the package file — a later\n step owns that. Finish your turn.\n <% if (it.processDiff.trim()) { %>\n\n ## Diff under review\n\n ```diff\n <%~ it.processDiff %>\n ```\n <% } %>\n on:\n \"A .gtd/SPEC_FEEDBACK.md\": spec-fix\n \"M .gtd/SPEC_FEEDBACK.md\": spec-fix\n \"D .gtd/SPEC_FEEDBACK.md\": closing\n \"C\": closing\n\n spec-fix:\n actor: agent\n file: <%= it.vars.specFeedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.specFeedbackFile %>`, which this prompt tells you to address\n and then delete.\n\n Read `<%= it.vars.specFeedbackFile %>` (the reviewer's concerns about the\n current package) and the package spec (`<%= it.read(it.vars.nextFile) %>`),\n then fix the code to resolve every concern. Keep the change focused.\n\n Delete `<%= it.vars.specFeedbackFile %>` once every concern is addressed.\n Leave everything else uncommitted and finish your turn.\n on:\n \"* **\": adv-checking\n\n closing:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn (the package closer) — remove the just-reviewed package\n # file (its path is in NEXT.md) plus any leftover spec feedback, so\n # `picking` selects the NEXT package (or falls through to review when the\n # queue is empty). Reached on approval (spec-review clean) and on the\n # spec-review retry cap (force-close, deferring the concern to the tail).\n set +e\n pkg=$(cat <%~ it.vars.nextFile %> 2>/dev/null)\n [ -n \"$pkg\" ] && rm -f \"$pkg\"\n rm -f <%~ it.vars.specFeedbackFile %> <%~ it.vars.nextFile %>\n on:\n \"* **\": picking\n\n # ── Shared health segment (simple build, feedback loop, code-only edits) ──\n checking:\n actor: check\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite; a red run records .gtd/FEEDBACK.md, a\n # green run cleans it up. The `on` rules decide what that means.\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": fixing\n \"M .gtd/FEEDBACK.md\": fixing\n \"D .gtd/FEEDBACK.md\": reviewing\n \"C\": reviewing\n\n fixing:\n actor: agent\n file: <%= it.vars.feedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: fix\n retry:\n max: 3\n otherwise: escalate\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.feedbackFile %>`, which this prompt tells you to address.\n\n Read `<%= it.vars.feedbackFile %>` (the failing test output) and fix the\n code so the suite passes. Keep the change focused — do not refactor\n unrelated code. If the feedback is wrong, empty or delete\n `<%= it.vars.feedbackFile %>` instead of \"fixing\" a non-issue.\n\n Leave everything uncommitted and finish your turn — do not commit.\n on:\n \"* **\": checking\n\n escalate:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The agent could not get the check to pass after repeated attempts.\n `<%= it.vars.feedbackFile %>` holds the last failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: checking\n describe: >-\n Fix the failure yourself — edit the code and/or `.gtd/FEEDBACK.md` —\n to re-run the check (**checking**).\n\n # ── Green-baseline gate: `gtd review` entry ───────────────────────────────\n # `gtd review <commitish>` enters HERE (reviewEntry), not `reviewing`. It runs\n # the suite on HEAD first; green proceeds to `reviewing`, red halts. The\n # `Gtd-Review-Base:` trailer rides on this state's entry commit, so the review\n # window / incremental-diff machinery downstream is unchanged.\n review-start-check:\n actor: check\n reviewEntry: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite before reviewing; a red run records\n # .gtd/FEEDBACK.md (halt), a green run cleans it up (proceed to reviewing).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": review-start-blocked\n \"M .gtd/FEEDBACK.md\": review-start-blocked\n \"D .gtd/FEEDBACK.md\": reviewing\n \"C\": reviewing\n\n review-start-blocked:\n actor: human\n file: <%= it.vars.feedbackFile %>\n message: |\n The test baseline is red — gtd will not start a review on a broken suite.\n `<%= it.vars.feedbackFile %>` holds the failing output.\n\n What each change does next (then run `gtd step human`):\n <% it.edges.forEach(function (e) { if (e.describe) { %>\n <%~ \"- \" + e.describe + \"\\n\" %>\n <% } }) %>\n on:\n \"* **\":\n to: review-start-check\n describe: >-\n Fix the failing tests — edit the code and/or `.gtd/FEEDBACK.md` — to\n re-run the baseline check (**review-start-check**).\n\n # ── Green-baseline gate: `gtd fix` entry ──────────────────────────────────\n # `gtd fix` enters HERE (fixEntry): run the suite, then a red run drops\n # straight into the shared `fixing` loop (-> checking -> review + squash\n # tail); a green run is a no-op back to `idle` (nothing to fix).\n fix-check:\n actor: check\n fixEntry: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — run the suite to find what needs fixing; a red run\n # records .gtd/FEEDBACK.md (-> fixing), a green run cleans it up (-> idle).\n set +e\n mkdir -p .gtd\n # Hoist the feedback path once, at the TOP: Eta's autoTrim eats the\n # newline after an interpolation tag, so no tag may be the last token on\n # a line — it would glue the next line's `else`/`fi` onto it and break\n # the script. Below this point everything is plain bash.\n feedback=\"<%~ it.vars.feedbackFile %>\"\n <%~ it.vars.testCommand %> > .gtd/.check-output 2>&1\n code=$?\n if [ \"$code\" -ne 0 ]; then\n if [ -s .gtd/.check-output ]; then\n mv .gtd/.check-output \"$feedback\"\n else\n rm -f .gtd/.check-output\n printf 'the test command failed with exit code %s and produced no output.' \"$code\" > \"$feedback\"\n fi\n else\n rm -f .gtd/.check-output\n rm -f \"$feedback\"\n fi\n on:\n \"A .gtd/FEEDBACK.md\": fixing\n \"M .gtd/FEEDBACK.md\": fixing\n \"D .gtd/FEEDBACK.md\": idle\n \"C\": idle\n\n # ── Shared tail: agent review -> human review -> squash finale ────────────\n reviewing:\n actor: agent\n file: <%= it.vars.reviewFile %>\n mode: review\n model: <%= it.vars.plannerModel %>\n memory: review\n # `gtd review <commitish>` (a plain non-gtd branch, e.g. a colleague's PR)\n # does NOT enter here directly — it enters `review-start-check` (reviewEntry)\n # first, which runs the green-baseline gate and, once green, transitions\n # here. The `Gtd-Review-Base:` trailer rides on that entry commit (the\n # process's oldest), so everything below still reuses the same\n # reviewing/await-review/feedback machinery over <commitish>..HEAD.\n prompt: |\n You are an autonomous coding agent. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.reviewFile %>`, which this prompt tells you to write.\n\n Write `<%= it.vars.reviewFile %>` to help a human review the diff below in\n this EXACT format:\n\n - First non-blank line: `# Review: <%= it.currentCommit.slice(0, 7) %>`\n - Somewhere in the document: `<!-- base: <%= it.startCommit %> -->`\n - At least one `## <Chunk Title>` heading, grouping hunks semantically\n (same feature/refactor/fix, even across files) — a short explanation of\n what changed and why, then one `- [ ] ./path/to/file.ts#42 — note` file\n pointer per hunk (checkboxes are for the human to tick, not you; every\n path is `./`-relative, with an optional `#line` and an optional\n ` — note`).\n\n The diff below is `it.reviewDiff` — on a feedback round it covers ONLY the\n changes made since the previous review, so you review just what changed,\n not items already signed off. Leave `<%= it.vars.reviewFile %>`\n uncommitted and finish your turn.\n <% if (it.reviewDiff.trim()) { %>\n\n ## Full diff under review\n\n ```diff\n <%~ it.reviewDiff %>\n ```\n <% } %>\n on:\n \"* **\": await-review\n\n await-review:\n actor: human\n file: <%= it.vars.reviewFile %>\n mode: review\n # While the cycle rests here, gtd opens a \"review checkout window\": raw HEAD\n # is rewound to the review base (the most-recent `review-deciding` commit —\n # so a feedback round shows only `last-review..HEAD` — or the process start\n # on the first review) with the working tree untouched, surfacing the diff\n # as ordinary uncommitted changes. It closes on the next invocation.\n #\n # Every human step here routes to `review-deciding`, which decides sign-off\n # vs. feedback from the step's CONTENT (a comment, not a tick). Ticking a box\n # only records \"I reviewed this hunk\". Two dead ends can't be told apart by a\n # file-pattern edge, so the sign-off gate (`enforceReviewSignoffGate` in\n # src/program.ts) catches them BEFORE the step commits and refuses: an\n # unfinished review (a box still `- [ ]` with no comment) and a deleted\n # REVIEW.md.\n reviewWindow: true\n message: |\n `<%= it.vars.reviewFile %>` holds the review record for the cycle — one\n `- [ ]` checkbox per reviewable item, grouped into chunks. Tick a box\n (`- [x]`) as you review each hunk; ticking only records that you've read\n it, it is not sign-off.\n\n When you've been through the whole diff, run `gtd step human`:\n\n - Tick EVERY box and leave no comment — no note in\n `<%= it.vars.reviewFile %>`, no code edit — to sign off and collapse the\n cycle into one commit (**squashing**).\n - Leave a comment to request changes — a note on a\n `<%= it.vars.reviewFile %>` line, or a direct code edit — to send it to a\n build + re-review round (**review-deciding** → **feedback-building**). A\n code edit counts as your own fix: the agent completes the follow-through\n it implies and never reverts your lines.\n\n Stepping with a box still unticked and no comment is refused (finish\n reviewing first); so is deleting `<%= it.vars.reviewFile %>`.\n on:\n \"* **\": review-deciding\n\n review-deciding:\n actor: check\n file: <%= it.vars.reviewFile %>\n mode: review\n # Anchors the INCREMENTAL review base: its most-recent in-process commit is\n # the point the previous review round ended, so the next `reviewing` turn\n # (and the review checkout window) covers only the changes since then. On\n # the first review there is no such commit, so the base is the cycle start.\n reviewBase: true\n script: |\n #!/usr/bin/env bash\n # gtd check turn — decide the human's review step from its CONTENT. HEAD is\n # the human's `await-review -> review-deciding` commit; HEAD^ is the\n # `reviewing` commit that wrote the agent's original REVIEW.md (the sign-off\n # gate refuses an incomplete step, so review-deciding is entered exactly\n # once per round — nothing commits in between). It is FEEDBACK when the\n # human left a comment: a note in REVIEW.md (any edit beyond a \"[ ]\"->\"[x]\"\n # tick) OR a hand-edit to any non-.gtd/ file this round. Otherwise it is a\n # clean sign-off. This turn only CAPTURES the raw material into REVIEW_RAW.md\n # (the `feedback-collecting` agent then turns it into instructions); it does\n # NOT interpret it. Either way, remove REVIEW.md; what the resulting diff\n # MEANS is decided by this state's own `on` rules — the A/M REVIEW_RAW.md\n # rows are declared BEFORE the D REVIEW.md row so a feedback round (which\n # also deletes REVIEW.md) is captured as feedback, not mistaken for a\n # sign-off.\n set +e\n mkdir -p .gtd\n # Hoist the paths once, at the TOP: Eta's autoTrim eats the newline after\n # an interpolation tag, so no tag may be the last token on a line — it\n # would glue the next line onto it and break the script. Below this point\n # everything is plain bash.\n reviewFile=\"<%~ it.vars.reviewFile %>\"\n reviewRawFile=\"<%~ it.vars.reviewRawFile %>\"\n # Which non-.gtd/ files did the human hand-edit this round?\n codeFiles=$(git diff-tree --no-commit-id --name-only -r HEAD | grep -v '^\\.gtd/')\n # A note is any REVIEW.md change beyond a checkbox flip: normalize every\n # \"[ ]\"/\"[x]\" to a placeholder, then compare the agent's original (HEAD^)\n # against the human's version (HEAD).\n notes=\"\"\n before=$(git show \"HEAD^:$reviewFile\" 2>/dev/null | sed -E 's/\\[[ xX]\\]/[_]/g')\n after=$(git show \"HEAD:$reviewFile\" 2>/dev/null | sed -E 's/\\[[ xX]\\]/[_]/g')\n if [ \"$before\" != \"$after\" ]; then notes=1; fi\n if [ -n \"$codeFiles\" ] || [ -n \"$notes\" ]; then\n {\n echo \"Raw review material captured for classification. The human reviewed the diff and left the feedback below; a downstream agent turns it into an instruction list. This file is machine-captured input, not instructions.\"\n if [ -n \"$notes\" ]; then\n echo\n echo \"## Notes the human added to REVIEW.md this round\"\n echo\n echo '```diff'\n git show HEAD --format= -- \"$reviewFile\"\n echo '```'\n fi\n if [ -n \"$codeFiles\" ]; then\n echo\n echo \"## Files the human hand-edited this round (already committed)\"\n echo\n echo '```diff'\n git show HEAD --format= -- $codeFiles\n echo '```'\n fi\n } > \"$reviewRawFile\"\n fi\n rm -f \"$reviewFile\"\n on:\n \"A .gtd/REVIEW_RAW.md\": feedback-collecting\n \"M .gtd/REVIEW_RAW.md\": feedback-collecting\n \"D .gtd/REVIEW.md\": squashing\n\n feedback-collecting:\n actor: agent\n file: <%= it.vars.reviewFeedbackFile %>\n model: <%= it.vars.plannerModel %>\n memory: review\n prompt: |\n You are an autonomous coding agent turning raw review feedback into an\n explicit instruction list for a builder. `.gtd/` holds this workflow's own\n state — never create, edit, or delete anything under `.gtd/` except\n `<%= it.vars.reviewRawFile %>` (delete it when done) and\n `<%= it.vars.reviewFeedbackFile %>` (write it). Do NOT change any other\n file — you classify, you do not build.\n\n The raw review material is: <%~ it.read(it.vars.reviewRawFile) %>\n\n Classify every piece of it into `<%= it.vars.reviewFeedbackFile %>` as a\n flat, numbered instruction list. Each item is `N. ./path/to/file.ts#line —\n <imperative>`. Read the two RAW sections and apply these rules exactly:\n\n 1. NOTES the human added to REVIEW.md — each note is a MANDATORY change,\n regardless of whether its checkbox is ticked (ticking means only \"I read\n this hunk\", never sign-off). Anchor each to the `./path#line` its review\n item names (or the chunk it sits under). Emit it as a concrete\n imperative.\n 2. Every COMMENT the human ADDED this round (a `+` line that is a code\n comment, in the hand-edited files) is a MANDATORY instruction the human\n is giving the builder — even a plain-prose one, even if its box is\n ticked. Emit an imperative to satisfy it and note that the comment line\n itself must be REMOVED once addressed. If a comment turns out to describe\n behaviour the code already has, the instruction is still \"confirm the\n code matches and remove the comment line\".\n 3. Every NON-comment code line the human hand-edited is an already-committed\n INTENT, NOT a do-then-delete item. Emit an instruction that names those\n files and says: their lines are final — complete ONLY the follow-through\n they imply (callers, tests, types, docs) and NEVER revert or rewrite\n them. Do not turn their own edit into a task.\n\n Split each hand-edited hunk per line: comment `+` lines follow rule 2, the\n surrounding real code follows rule 3.\n\n If — and only if — nothing in the raw material is actionable (e.g. the human\n left only an approving remark), write `<%= it.vars.reviewFeedbackFile %>`\n containing exactly one line: `NOTHING ACTIONABLE — <one-sentence reason>`.\n Never invent work to satisfy a non-actionable remark.\n\n Delete `<%= it.vars.reviewRawFile %>`, leave everything else uncommitted,\n and finish your turn.\n on:\n \"A .gtd/REVIEW_FEEDBACK.md\": feedback-building\n \"M .gtd/REVIEW_FEEDBACK.md\": feedback-building\n\n feedback-building:\n actor: agent\n file: <%= it.vars.reviewFeedbackFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n # Refuse a work-free turn: a step whose only pending change is deleting the\n # instructions file (the original \"captured then discarded\" bug). The edge\n # gate (`enforceFeedbackProgressGate` in src/program.ts) reads this flag and\n # exempts a `NOTHING ACTIONABLE` sentinel (a non-actionable review round,\n # which legitimately makes no code change). The pure engine carries it inert.\n requireProgress: true\n prompt: |\n You are an autonomous coding agent addressing review feedback. `.gtd/`\n holds this workflow's own state — never create, edit, or delete anything\n under `.gtd/` except `<%= it.vars.reviewFeedbackFile %>`, which this\n prompt tells you to address and then delete.\n\n The instructions to implement are: <%~ it.read(it.vars.reviewFeedbackFile) %>\n\n This is a flat instruction list, not a diff — execute every item exactly as\n written, no Q&A, no re-planning, using TDD discipline:\n\n - An item that says the human's own lines are final: build ON TOP of them to\n complete only the follow-through it names (callers, tests, types, docs).\n NEVER revert or rewrite the lines they already committed.\n - An item derived from a human comment: satisfy it AND delete that comment\n line from the code (the human's review comments are transient — none of\n them survive this round).\n\n If the file's sole content is a `NOTHING ACTIONABLE` line, make no code\n change; just delete the instructions file.\n\n Delete `<%= it.vars.reviewFeedbackFile %>` once every item is addressed.\n Leave everything else uncommitted and finish your turn. Deleting the\n instructions file WITHOUT making the changes it asks for is refused — the\n feedback must actually be addressed.\n on:\n \"* **\": checking\n\n squashing:\n actor: agent\n file: <%= it.vars.commitMsgFile %>\n model: <%= it.vars.coderModel %>\n memory: build\n prompt: |\n You are an autonomous coding agent. The cycle is approved and done.\n `.gtd/` holds this workflow's own state — never create, edit, or delete\n anything under `.gtd/` except `<%= it.vars.commitMsgFile %>`, which this\n prompt tells you to write.\n\n Leave `<%= it.vars.commitMsgFile %>` uncommitted and finish your turn —\n entering this file squashes everything this process retains into one\n commit using its content as the message. The diff below is exactly what\n that commit will contain: `it.retainedDiff`, the changes THIS process\n made (its trace/retry boundary onward). For a normal build cycle that is\n the whole feature; for a `gtd review` process it is only the fixes made\n during the review — NOT the changeset that was under review.\n <% if (it.retainedDiff.trim()) { %>\n\n Write `<%= it.vars.commitMsgFile %>` with ONE conventional-commits message\n for the changes below (subject line `type(scope): subject`, imperative\n mood, <= 72 characters; a body explaining the why, trade-offs, and key\n decisions). Plain text, no markdown wrapper.\n\n ## Retained diff\n\n ```diff\n <%~ it.retainedDiff %>\n ```\n <% } else { %>\n\n This process retained NO changes (a clean review sign-off with no fixes).\n Write `<%= it.vars.commitMsgFile %>` with exactly this one line and\n nothing else:\n\n chore: human review\n <% } %>\n on:\n \"A .gtd/COMMIT_MSG.md\": done\n \"M .gtd/COMMIT_MSG.md\": done\n\n done:\n commit: |\n <%~ it.read(it.vars.commitMsgFile) %>\n\n Token cost: <%= it.processCost %>\n <% it.processCostByModel.forEach(function(m){ %>\n - <%= m.model %>: <%= m.cost %>\n <% }) %>\n";
|
|
191562
|
-
//#endregion
|
|
191563
|
-
//#region src/workflows/templates.ts
|
|
191564
|
-
/**
|
|
191565
|
-
* The `$schema` URL editors resolve for `.gtdrc.json` completion/validation —
|
|
191566
|
-
* written as the first key of every `gtd init` config (see `renderInitConfig`).
|
|
191567
|
-
*/
|
|
191568
|
-
const SCHEMA_URL = "https://raw.githubusercontent.com/pmelab/gtd/main/schema.json";
|
|
191569
|
-
/**
|
|
191570
|
-
* The repo-root-relative directory `gtd init` writes each agent state's prompt
|
|
191571
|
-
* into as a standalone, editable Markdown file (see `renderInitScaffold`). The
|
|
191572
|
-
* scaffolded `.gtdrc.json` references these via `./gtd-prompts/<state>.md`
|
|
191573
|
-
* content-value file references, which `compileWorkflowConfig` inlines at load
|
|
191574
|
-
* time (`resolveContent` in `src/PatternConfig.ts`) — so editing a prompt file
|
|
191575
|
-
* changes the workflow with no config edit.
|
|
191576
|
-
*/
|
|
191577
|
-
const PROMPTS_DIR = "gtd-prompts";
|
|
191578
|
-
/**
|
|
191579
|
-
* The top-level `modes:` block `gtd init` SEEDS into the scaffolded
|
|
191580
|
-
* `.gtdrc.json` as a ready-to-edit suggestion: a `format:` command for each
|
|
191581
|
-
* built-in steering-file mode the bundled template uses (`qa` for the plan /
|
|
191582
|
-
* open-questions files, `review` for REVIEW.md), so a fresh project's steering
|
|
191583
|
-
* files are auto-formatted with Prettier before gtd validates them. Only
|
|
191584
|
-
* `format:` is declared — gtd's built-in `qa`/`review` validators still do the
|
|
191585
|
-
* validating (the two halves layer independently — see STATES.md §12 /
|
|
191586
|
-
* docs/configuration.md `modes:`). gtd ships no formatter, so this is the one
|
|
191587
|
-
* place a default is suggested; a project edits or drops it freely (swap
|
|
191588
|
-
* Prettier for dprint, point at a script, delete the key).
|
|
191589
|
-
*
|
|
191590
|
-
* Seeded only by `renderInitScaffold` (the real `gtd init` write path), NOT by
|
|
191591
|
-
* `renderInitConfig`: the latter is reused as a hermetic test fixture (the
|
|
191592
|
-
* `Given the workflow` step) that must not depend on Prettier being installed
|
|
191593
|
-
* or spawn a subprocess at every steering-file gate.
|
|
191594
|
-
*/
|
|
191595
|
-
const MODES_SUGGESTION = {
|
|
191596
|
-
qa: { format: "npx prettier --write <%= it.file %>" },
|
|
191597
|
-
review: { format: "npx prettier --write <%= it.file %>" }
|
|
191598
|
-
};
|
|
191599
|
-
/**
|
|
191600
|
-
* The single bundled workflow template `gtd init` scaffolds — the raw YAML text
|
|
191601
|
-
* of `unified.yaml`, imported as a string (tsdown's `.yaml` text loader / the
|
|
191602
|
-
* vitest `rawMd` transform — see tsdown.config.ts / tests/vitest.rawMd.ts), so
|
|
191603
|
-
* this module never touches the filesystem: it works identically in the dev
|
|
191604
|
-
* checkout, under `vitest`, and inside the single-file `dist/gtd.bundle.mjs`
|
|
191605
|
-
* build. gtd ships NO default workflow and no longer offers a choice of
|
|
191606
|
-
* templates — `gtd init` takes no argument.
|
|
191607
|
-
*/
|
|
191608
|
-
const UNIFIED_WORKFLOW = unified_default;
|
|
191609
|
-
/**
|
|
191610
|
-
* Render everything `gtd init` writes. Like `renderInitConfig`, but each agent
|
|
191611
|
-
* state's inline `prompt:` is EXTRACTED into a standalone
|
|
191612
|
-
* `gtd-prompts/<state>.md` file and the config value is rewritten to a
|
|
191613
|
-
* `./gtd-prompts/<state>.md` file reference — `compileWorkflowConfig` inlines
|
|
191614
|
-
* it back at load time (`resolveContent`), so the workflow behaves identically
|
|
191615
|
-
* to the fully-inline `renderInitConfig` form while the prompts stay editable
|
|
191616
|
-
* as ordinary Markdown. Only `prompt:` content is externalized: human
|
|
191617
|
-
* `message:` blocks, check `script:` bodies, and the `done` `commit:` template
|
|
191618
|
-
* remain inline in the config (they are workflow mechanics, not prompts). The
|
|
191619
|
-
* bundled YAML template itself stays fully inline (it ships inside the
|
|
191620
|
-
* single-file bundle); this function is the only place the split happens, at
|
|
191621
|
-
* scaffold time.
|
|
191622
|
-
*
|
|
191623
|
-
* It also seeds a top-level `modes:` block (`MODES_SUGGESTION`) — a ready-to-
|
|
191624
|
-
* edit Prettier `format:` for the built-in `qa`/`review` steering-file modes —
|
|
191625
|
-
* so a fresh project auto-formats its steering files out of the box. This lives
|
|
191626
|
-
* here rather than in `renderInitConfig` so the latter stays a hermetic test
|
|
191627
|
-
* fixture (see `MODES_SUGGESTION`).
|
|
191628
|
-
*/
|
|
191629
|
-
const renderInitScaffold = () => {
|
|
191630
|
-
const workflow = (0, import_dist$1.parse)(UNIFIED_WORKFLOW);
|
|
191631
|
-
const prompts = [];
|
|
191632
|
-
for (const [stateName, state] of Object.entries(workflow.states ?? {})) if (typeof state.prompt === "string") {
|
|
191633
|
-
const path = `${PROMPTS_DIR}/${stateName}.md`;
|
|
191634
|
-
prompts.push({
|
|
191635
|
-
path,
|
|
191636
|
-
content: state.prompt
|
|
191637
|
-
});
|
|
191638
|
-
state.prompt = `./${path}`;
|
|
191639
|
-
}
|
|
191640
|
-
return {
|
|
191641
|
-
config: JSON.stringify({
|
|
191642
|
-
$schema: SCHEMA_URL,
|
|
191643
|
-
modes: MODES_SUGGESTION,
|
|
191644
|
-
workflow
|
|
191645
|
-
}, null, 2) + "\n",
|
|
191646
|
-
prompts
|
|
191647
|
-
};
|
|
191648
|
-
};
|
|
191649
|
-
//#endregion
|
|
191650
191644
|
//#region node_modules/eta/dist/index.mjs
|
|
191651
191645
|
var EtaError = class extends Error {
|
|
191652
191646
|
constructor(message) {
|
|
@@ -204616,11 +204610,13 @@ const GTD_VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
|
204616
204610
|
const HELP_TEXT = `Usage: gtd [command] [options]
|
|
204617
204611
|
|
|
204618
204612
|
Commands:
|
|
204619
|
-
init Scaffold a .gtdrc.json for this repo
|
|
204620
|
-
|
|
204621
|
-
|
|
204613
|
+
init Scaffold a minimal .gtdrc.json for this repo, seeding the
|
|
204614
|
+
default variables you are most likely to change (the test
|
|
204615
|
+
command) and a Prettier formatting suggestion. gtd runs its
|
|
204616
|
+
built-in workflow by default, so no workflow is written —
|
|
204617
|
+
add a workflow: key only to customize the machine itself.
|
|
204622
204618
|
Takes no argument. Run once per repo; refuses if a gtd
|
|
204623
|
-
config already exists. Leaves the
|
|
204619
|
+
config already exists. Leaves the file uncommitted for you
|
|
204624
204620
|
to review and commit
|
|
204625
204621
|
step <actor> Authenticate as <actor>, match the resolved rest's
|
|
204626
204622
|
declared patterns against the pending changes, and commit
|
|
@@ -204671,7 +204667,7 @@ const isEnveloped = (error) => typeof error === "object" && error !== null && er
|
|
|
204671
204667
|
* The stderr line for a CLI error (see `main.ts`): a `gtd: ` prefix UNLESS the
|
|
204672
204668
|
* message already carries one. Most gtd errors are authored with a
|
|
204673
204669
|
* `gtd:`/`gtd <cmd>:` prefix of their own (e.g. `gtd init: …`,
|
|
204674
|
-
* `gtd:
|
|
204670
|
+
* `gtd: unknown option …`), so a blind prepend produced a doubled
|
|
204675
204671
|
* `gtd: gtd: …`.
|
|
204676
204672
|
*/
|
|
204677
204673
|
const cliErrorLine = (error) => {
|
|
@@ -204751,20 +204747,19 @@ const runLspCommand = (argv, json) => gen(function* () {
|
|
|
204751
204747
|
yield* startLspServer();
|
|
204752
204748
|
});
|
|
204753
204749
|
/**
|
|
204754
|
-
* `gtd init`: scaffold a `.gtdrc.json`
|
|
204755
|
-
*
|
|
204756
|
-
*
|
|
204757
|
-
*
|
|
204758
|
-
*
|
|
204759
|
-
*
|
|
204760
|
-
*
|
|
204761
|
-
* the
|
|
204762
|
-
*
|
|
204763
|
-
*
|
|
204764
|
-
*
|
|
204765
|
-
*
|
|
204766
|
-
*
|
|
204767
|
-
* would otherwise capture).
|
|
204750
|
+
* `gtd init`: scaffold a MINIMAL `.gtdrc.json` seeding the default variables a
|
|
204751
|
+
* fresh project is most likely to change — the test command (`vars.testCommand`)
|
|
204752
|
+
* and a ready-to-edit Prettier formatting suggestion (`modes:`). It writes NO
|
|
204753
|
+
* `workflow:` key: gtd ships the unified workflow as its built-in default and
|
|
204754
|
+
* runs it whenever none is configured (see `src/Config.ts`), so there is
|
|
204755
|
+
* nothing to scaffold there — a project customizes the machine itself only by
|
|
204756
|
+
* adding a `workflow:` key. Takes NO argument. Dispatched like `lsp` — BEFORE
|
|
204757
|
+
* the closeReviewWindow/dispatch/openReviewWindow block — because it needs no
|
|
204758
|
+
* `ConfigService` and no review window. It still runs the repo-root guard (it
|
|
204759
|
+
* writes `.gtdrc.json` at the root) and refuses to clobber an existing config.
|
|
204760
|
+
* The file is left UNCOMMITTED, so the message warns to commit it before the
|
|
204761
|
+
* first `gtd step` (an uncommitted config counts as a pending change the
|
|
204762
|
+
* initial state's `* **` edge would otherwise capture).
|
|
204768
204763
|
*/
|
|
204769
204764
|
const runInitCommand = (argv, json, write) => gen(function* () {
|
|
204770
204765
|
const args = commandArgs(argv);
|
|
@@ -204777,21 +204772,11 @@ const runInitCommand = (argv, json, write) => gen(function* () {
|
|
|
204777
204772
|
const toError = (e) => e instanceof Error ? e : new Error(String(e));
|
|
204778
204773
|
const scaffold = renderInitScaffold();
|
|
204779
204774
|
yield* fs.writeFileString(join(root, ".gtdrc.json"), scaffold.config).pipe(mapError$1(toError));
|
|
204780
|
-
for (const prompt of scaffold.prompts) {
|
|
204781
|
-
const full = join(root, prompt.path);
|
|
204782
|
-
yield* fs.makeDirectory(dirname(full), { recursive: true }).pipe(mapError$1(toError));
|
|
204783
|
-
yield* fs.writeFileString(full, prompt.content).pipe(mapError$1(toError));
|
|
204784
|
-
}
|
|
204785
204775
|
if (json) write(JSON.stringify({
|
|
204786
204776
|
written: ".gtdrc.json",
|
|
204787
|
-
workflow: "unified",
|
|
204788
|
-
prompts: scaffold.prompts.map((p) => p.path),
|
|
204789
204777
|
inRepo
|
|
204790
204778
|
}) + "\n");
|
|
204791
|
-
else
|
|
204792
|
-
const promptCount = scaffold.prompts.length;
|
|
204793
|
-
write(`Wrote .gtdrc.json with the bundled unified workflow, and its ${promptCount} agent prompt${promptCount === 1 ? "" : "s"} as editable Markdown under ${PROMPTS_DIR}/ (referenced from the config).\n\n` + (inRepo ? "Review and commit them before starting: an uncommitted .gtdrc.json (or prompt\nfile) counts as a pending change, so the initial state would capture it on the\nfirst step. Once committed, run `gtd step human` to begin.\n" : "This directory is not a git repository, so there is nothing to commit here. The\nconfig applies to any gtd repository nested below it — gtd discovers it by\nwalking up from the repository root. Run `gtd step human` from such a repo to\nbegin.\n"));
|
|
204794
|
-
}
|
|
204779
|
+
else write("Wrote .gtdrc.json seeding the default variables (the test command) and a\nPrettier formatting suggestion. gtd runs its built-in workflow by default — add\na workflow: key only if you want to customize the machine itself.\n\n" + (inRepo ? "Review and commit it before starting: an uncommitted .gtdrc.json counts as a\npending change, so the initial state would capture it on the first step. Once\ncommitted, run `gtd step human` to begin.\n" : "This directory is not a git repository, so there is nothing to commit here. The\nconfig applies to any gtd repository nested below it — gtd discovers it by\nwalking up from the repository root. Run `gtd step human` from such a repo to\nbegin.\n"));
|
|
204795
204780
|
});
|
|
204796
204781
|
/**
|
|
204797
204782
|
* Resolve HEAD's rest, the current process run, and the template context for
|
|
@@ -205413,7 +205398,7 @@ const dispatchKnownSubcommand = (sub, argv, json, write, cost, model) => {
|
|
|
205413
205398
|
* `status` / `validate` / `mermaid` (see `src/Edge.ts` and
|
|
205414
205399
|
* `docs/design/pattern-machine-plan.md` §3),
|
|
205415
205400
|
* plus `lsp` and `init` — both dispatched before the config-reading
|
|
205416
|
-
* path since
|
|
205401
|
+
* path since neither needs to touch the config. Bare `gtd` or an
|
|
205417
205402
|
* unknown subcommand is a usage error. Shared setup (argv parsing, the
|
|
205418
205403
|
* repo-root guard) lives here; each subcommand's own logic is a named
|
|
205419
205404
|
* `run*Command` function above.
|
package/docs/cli.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
Usage: gtd [command] [options]
|
|
5
5
|
|
|
6
6
|
Commands:
|
|
7
|
-
init Scaffold a .gtdrc.json for this repo
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
to review and commit
|
|
7
|
+
init Scaffold a minimal .gtdrc.json for this repo, seeding a
|
|
8
|
+
testCommand var (npm test) and a ready-to-edit Prettier
|
|
9
|
+
formatting suggestion under modes:. Writes no workflow — gtd
|
|
10
|
+
runs the bundled unified workflow as its built-in default.
|
|
11
|
+
Takes no argument. Refuses if a gtd config already exists.
|
|
12
|
+
Leaves the file uncommitted for you to review and commit
|
|
13
13
|
step <actor> Authenticate as <actor>, match the resolved rest's
|
|
14
14
|
declared patterns against the pending changes, and commit
|
|
15
15
|
(or squash) the one resulting transition. Pass
|
|
@@ -65,15 +65,17 @@ mistyped flag can never degrade a JSON caller to plain-text mode. A bare
|
|
|
65
65
|
|
|
66
66
|
## `gtd init`
|
|
67
67
|
|
|
68
|
-
Scaffolds a `.gtdrc.json` at the repository root
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
Scaffolds a **minimal** `.gtdrc.json` at the repository root, plus a `$schema`
|
|
69
|
+
link. It writes **no** `workflow:` key — gtd runs the bundled **unified**
|
|
70
|
+
workflow as its built-in default, so a state command works out of the box with
|
|
71
|
+
no config and no init at all. What `gtd init` seeds is the two things most
|
|
72
|
+
projects tune: a `vars: { "testCommand": "npm test" }` entry (the var the
|
|
73
|
+
bundled workflow's check script reads) and a ready-to-edit `modes:` block
|
|
74
|
+
suggesting a Prettier `format:` for each built-in steering-file mode
|
|
75
|
+
(`qa`/`review`). It takes **no argument** — passing one is a usage error
|
|
76
|
+
(`gtd init: too many arguments — init takes no argument`).
|
|
77
|
+
|
|
78
|
+
The bundled default has four entry points — each behind a green-baseline gate
|
|
77
79
|
that runs the suite before starting — into one shared review/squash tail (see
|
|
78
80
|
[STATES.md §10](../STATES.md#10-the-bundled-workflow-templates)): creating
|
|
79
81
|
`.gtd/TODO.md` starts the simple flow (planning → building → checking), creating
|
|
@@ -81,15 +83,16 @@ that runs the suite before starting — into one shared review/squash tail (see
|
|
|
81
83
|
per-package parallel build, agentic spec-review), `gtd review <commitish>`
|
|
82
84
|
enters review directly, and `gtd fix` goes straight into repairing failing
|
|
83
85
|
tests. A red baseline halts at a `*-start-blocked` gate rather than starting new
|
|
84
|
-
work.
|
|
86
|
+
work. To CUSTOMIZE that machine, add your own `workflow:` key (a full definition
|
|
87
|
+
— there is no `extends`/merge); see
|
|
88
|
+
[Configuration](configuration.md#the-workflow-key).
|
|
85
89
|
|
|
86
90
|
The file is written **uncommitted**; review and commit it before your first
|
|
87
91
|
`gtd step` (an uncommitted `.gtdrc.json` is a pending change the initial state
|
|
88
92
|
would otherwise capture). `gtd init` refuses if the repo root already has its
|
|
89
|
-
own gtd config (a global/ancestor config, e.g. `~/.gtdrc`, does not count)
|
|
90
|
-
requires the repository root
|
|
91
|
-
|
|
92
|
-
`{"written":".gtdrc.json","workflow":"unified","prompts":[…]}`. See
|
|
93
|
+
own gtd config (a global/ancestor config, e.g. `~/.gtdrc`, does not count) and
|
|
94
|
+
requires the repository root (or a directory outside any repo). `--json` prints
|
|
95
|
+
`{"written":".gtdrc.json","inRepo":true}`. See
|
|
93
96
|
[Configuration](configuration.md#gtd-init).
|
|
94
97
|
|
|
95
98
|
## `gtd step <actor> [--cost=<n>] [--model=<name>]`
|
|
@@ -460,11 +463,11 @@ naming the state instead — bind it to an editor keybinding for a "jump to the
|
|
|
460
463
|
active steering file" command.
|
|
461
464
|
|
|
462
465
|
Dispatched before the repository-root guard and the config-reading path — the
|
|
463
|
-
server needs no git/workflow state of its own (like `gtd init`, it
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
466
|
+
server needs no git/workflow state of its own (like `gtd init`, it needs no
|
|
467
|
+
config to run). Rejects `--json` (exit 1, `gtd lsp does not accept --json`) and
|
|
468
|
+
extra positional arguments — it's a long-running server, not a state command.
|
|
469
|
+
Runs until the client disconnects (the LSP `exit` notification), then exits
|
|
470
|
+
cleanly.
|
|
468
471
|
|
|
469
472
|
## Error envelope
|
|
470
473
|
|
package/docs/configuration.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
gtd reads
|
|
4
|
-
[cosmiconfig](https://github.com/cosmiconfig/cosmiconfig). gtd ships
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`
|
|
9
|
-
(
|
|
3
|
+
gtd reads an optional `.gtdrc` config file via
|
|
4
|
+
[cosmiconfig](https://github.com/cosmiconfig/cosmiconfig). gtd ships the bundled
|
|
5
|
+
**unified** workflow as its **built-in default**: with no `workflow:` configured
|
|
6
|
+
anywhere in the cwd→home config chain, that default is used automatically, so a
|
|
7
|
+
state command works out of the box with no config at all.
|
|
8
|
+
[`gtd init`](#gtd-init) is optional — it seeds a minimal `.gtdrc.json` with the
|
|
9
|
+
two things most projects tune (a `testCommand` var and a Prettier formatting
|
|
10
|
+
suggestion), not the workflow. To CUSTOMIZE the machine itself, add your own
|
|
11
|
+
[`workflow:`](#the-workflow-key) key. Supported filenames (searched in this
|
|
12
|
+
order):
|
|
10
13
|
|
|
11
14
|
- `.gtdrc`
|
|
12
15
|
- `.gtdrc.json`
|
|
@@ -19,10 +22,11 @@ prompts as editable Markdown under `gtd-prompts/`). A state command run with no
|
|
|
19
22
|
|
|
20
23
|
v3's `.gtdrc` has exactly three blessed top-level keys:
|
|
21
24
|
|
|
22
|
-
- **`workflow`** (object,
|
|
23
|
-
|
|
24
|
-
`src/PatternConfig.ts`. Absent =
|
|
25
|
-
|
|
25
|
+
- **`workflow`** (object, optional) — the whole machine definition (its states,
|
|
26
|
+
plus its own `vars:` defaults and `modes:`), compiled by
|
|
27
|
+
`src/PatternConfig.ts`. Absent = gtd's built-in default (the bundled unified
|
|
28
|
+
workflow) is used. Declare it to fully REPLACE that default with your own
|
|
29
|
+
machine (there is no `extends`/merge). See
|
|
26
30
|
["The `workflow:` key" below](#the-workflow-key) for its schema.
|
|
27
31
|
- **`vars`** (object, optional) — a flat `name -> scalar` map, one layer of the
|
|
28
32
|
merged `it.vars` every template sees — see ["Variables"](#variables) below.
|
|
@@ -52,11 +56,12 @@ interprets.
|
|
|
52
56
|
> verify a change compiles. This section is the exhaustive schema reference
|
|
53
57
|
> behind it.
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
no merge-over-a-built-in. The
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
A declared `workflow:` key fully REPLACES gtd's built-in default — there is no
|
|
60
|
+
`extends`, no merge-over-a-built-in. The built-in default is itself a YAML asset
|
|
61
|
+
(`src/workflows/unified.yaml`) compiled through the exact same compiler
|
|
62
|
+
(`compileWorkflowConfig`) your own `workflow:` value goes through — no
|
|
63
|
+
privileged code path — so you can materialize it into config form as a starting
|
|
64
|
+
point to edit (`renderInitConfig` in `src/workflows/templates.ts`). Its shape:
|
|
60
65
|
|
|
61
66
|
```yaml
|
|
62
67
|
workflow:
|
|
@@ -107,8 +112,8 @@ root, discovers the parent `.gtdrc` by walking up the directory chain (see
|
|
|
107
112
|
level's `./`-relative references against that level's own directory. When
|
|
108
113
|
workflows are layered across levels, every reference resolves against the file
|
|
109
114
|
that wrote it, so a parent's `./gtd-prompts/x.md` and a child's never collide.
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
(This is a capability of a `.gtdrc` you write yourself — `gtd init` seeds only
|
|
116
|
+
`vars:`/`modes:`, not a `workflow:` with file references.)
|
|
112
117
|
|
|
113
118
|
```yaml
|
|
114
119
|
workflow:
|
|
@@ -380,16 +385,17 @@ So for a state declaring `mode: qa`:
|
|
|
380
385
|
| both | its `format:` | its `validate:` |
|
|
381
386
|
|
|
382
387
|
That is what makes the built-in modes extensible rather than all-or-nothing —
|
|
383
|
-
and the top-level key means a project can plug its formatter into the
|
|
384
|
-
|
|
385
|
-
itself. **`gtd init` seeds exactly this block by default** (the
|
|
386
|
-
suggestion below), so a fresh repo already formats its steering files —
|
|
387
|
-
drop it to taste. It
|
|
388
|
+
and the top-level key means a project can plug its formatter into the built-in
|
|
389
|
+
default workflow (or its own) without re-declaring a `modes:` block on the
|
|
390
|
+
workflow itself. **`gtd init` seeds exactly this block by default** (the
|
|
391
|
+
Prettier suggestion below), so a fresh repo already formats its steering files —
|
|
392
|
+
edit or drop it to taste. It is what a scaffolded `.gtdrc.json` contains
|
|
393
|
+
(`gtd init` writes no `workflow:` key — the built-in default is used):
|
|
388
394
|
|
|
389
395
|
```jsonc
|
|
390
|
-
// .gtdrc.json —
|
|
396
|
+
// .gtdrc.json — as scaffolded by `gtd init`: a testCommand var and the markdown formatter
|
|
391
397
|
{
|
|
392
|
-
"
|
|
398
|
+
"vars": { "testCommand": "npm test" },
|
|
393
399
|
"modes": {
|
|
394
400
|
"qa": { "format": "npx prettier --write <%= it.file %>" },
|
|
395
401
|
"review": { "format": "npx prettier --write <%= it.file %>" },
|
|
@@ -702,24 +708,21 @@ can still override with its own `.gtdrc`.
|
|
|
702
708
|
|
|
703
709
|
## `gtd init`
|
|
704
710
|
|
|
705
|
-
gtd ships
|
|
706
|
-
command works
|
|
711
|
+
gtd ships the bundled unified workflow as its **built-in default**, so a state
|
|
712
|
+
command works out of the box with **no** config and no init at all. `gtd init`
|
|
713
|
+
is therefore optional — it just seeds the two things most projects tune:
|
|
707
714
|
|
|
708
715
|
```bash
|
|
709
716
|
gtd init # takes no argument
|
|
710
717
|
```
|
|
711
718
|
|
|
712
|
-
`gtd init` writes a `.gtdrc.json` at the repository root
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
[file reference](#content-values-inline-or-a-file-reference) — gtd inlines it at
|
|
720
|
-
load time, so a prompt is editable Markdown and editing it changes the workflow
|
|
721
|
-
with no config edit. Human `message:` blocks and check `script:` bodies stay
|
|
722
|
-
inline in the config (they are workflow mechanics, not prompts).
|
|
719
|
+
`gtd init` writes a **minimal** `.gtdrc.json` at the repository root — a
|
|
720
|
+
`$schema` link (so editors pick up completion/validation), a
|
|
721
|
+
`vars: { "testCommand": "npm test" }` entry (the var the built-in workflow's
|
|
722
|
+
check script reads), and a ready-to-edit `modes:` formatting suggestion (below).
|
|
723
|
+
It writes **no** `workflow:` key — the built-in default is used until you
|
|
724
|
+
declare your own. It takes **no argument** — passing one is a usage error
|
|
725
|
+
(`gtd init: too many arguments — init takes no argument`).
|
|
723
726
|
|
|
724
727
|
`gtd init` writes only config — it derives no git state — so it need not run in
|
|
725
728
|
a git repository. It runs at a **repository root** or in a directory **outside
|
|
@@ -731,9 +734,9 @@ only to write into a repository **subdirectory**, where the upward config walk
|
|
|
731
734
|
would never find the file. Either way, it will not overwrite an existing config
|
|
732
735
|
at that directory (remove it first to re-scaffold).
|
|
733
736
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
+
The [`modes:`](#modes--pluggable-steering-file-modes) block it seeds is a
|
|
738
|
+
ready-to-edit suggestion — a Prettier `format:` for each built-in steering-file
|
|
739
|
+
mode the default workflow uses:
|
|
737
740
|
|
|
738
741
|
```jsonc
|
|
739
742
|
"modes": {
|
|
@@ -748,8 +751,8 @@ this is the one default it suggests: a fresh repo auto-formats its steering
|
|
|
748
751
|
files out of the box, and you edit or drop the block freely (swap Prettier for
|
|
749
752
|
dprint, point at a script, or delete the key).
|
|
750
753
|
|
|
751
|
-
The
|
|
752
|
-
(all walked through in
|
|
754
|
+
The built-in default workflow has three entry points into a shared review/squash
|
|
755
|
+
tail (all walked through in
|
|
753
756
|
[STATES.md §10](../STATES.md#10-the-bundled-workflow-templates)):
|
|
754
757
|
|
|
755
758
|
- **the simple flow** — creating `.gtd/TODO.md` starts idle → planning ⇄
|
|
@@ -763,20 +766,15 @@ The one bundled template has three entry points into a shared review/squash tail
|
|
|
763
766
|
review a foreign branch.
|
|
764
767
|
|
|
765
768
|
Both file-created flows converge on `reviewing` → `await-review`, and a full
|
|
766
|
-
sign-off squashes the whole cycle into one commit.
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
fails with:
|
|
776
|
-
|
|
777
|
-
```
|
|
778
|
-
gtd: no workflow configured — run `gtd init` to create .gtdrc.json
|
|
779
|
-
```
|
|
769
|
+
sign-off squashes the whole cycle into one commit. To CUSTOMIZE any of this, add
|
|
770
|
+
a [`workflow:`](#the-workflow-key) key that fully replaces the default.
|
|
771
|
+
|
|
772
|
+
The file is written **uncommitted** — review it, then commit `.gtdrc.json`
|
|
773
|
+
before your first `gtd step` (an uncommitted file is a pending change the
|
|
774
|
+
initial state's `* **` edge would otherwise capture). `gtd init` refuses if the
|
|
775
|
+
repo root already has its OWN gtd config (remove it first to re-init; a
|
|
776
|
+
global/ancestor config such as `~/.gtdrc` does not count) and requires the
|
|
777
|
+
repository root (or a directory outside any repo).
|
|
780
778
|
|
|
781
779
|
## A complete example
|
|
782
780
|
|
package/docs/development.md
CHANGED
|
@@ -31,7 +31,8 @@ registry to keep in sync: a workflow's content strings are either inline in its
|
|
|
31
31
|
YAML/`.gtdrc` or a `./`-relative file reference auto-inlined at config load
|
|
32
32
|
(`src/PatternConfig.ts`) — see
|
|
33
33
|
[Configuration](configuration.md#content-values-inline-or-a-file-reference). The
|
|
34
|
-
bundled workflow template (`src/workflows/unified.yaml`)
|
|
34
|
+
bundled workflow template (`src/workflows/unified.yaml`) gtd runs as its
|
|
35
|
+
built-in default (and materializes into config form via `renderInitConfig`) is
|
|
35
36
|
imported as raw text via tsdown's `.yaml`-as-text loader (`tsdown.config.ts`)
|
|
36
37
|
and compiled through the same path a `.gtdrc` `workflow:` key goes through
|
|
37
38
|
(`src/workflows/templates.ts`) — no privileged code path.
|
package/docs/upgrading.md
CHANGED
|
@@ -122,29 +122,25 @@ upgrading.
|
|
|
122
122
|
|
|
123
123
|
## How to adopt
|
|
124
124
|
|
|
125
|
-
`workflow:` is
|
|
126
|
-
upgrading
|
|
125
|
+
`workflow:` is **optional** — gtd ships the bundled **unified** workflow as its
|
|
126
|
+
built-in default, so after upgrading a repo works with **no** config and no init
|
|
127
|
+
at all. The default forks on which steering file you create: `.gtd/TODO.md`
|
|
128
|
+
starts the **simple flow** (a `planning` ⇄ `plan-review` plan-iteration loop,
|
|
129
|
+
direct `building`, a `checking`/`fixing` loop), while `.gtd/REQUIREMENTS.md`
|
|
130
|
+
starts the **advanced flow** (two-phase grilling ⇄ grilling-answer /
|
|
131
|
+
architecting ⇄ architecting-answer / decompose / picking / per-package build
|
|
132
|
+
with an agentic spec-review gate). Both converge on the same `reviewing` →
|
|
133
|
+
`await-review` tail, and a full sign-off squashes the whole cycle into one
|
|
134
|
+
commit (see [STATES.md §10](../STATES.md#10-the-bundled-workflow-templates)).
|
|
135
|
+
|
|
136
|
+
`gtd init` is now optional and no longer writes a workflow — it seeds only a
|
|
137
|
+
minimal `.gtdrc.json` (a `testCommand` var and a Prettier formatting
|
|
138
|
+
suggestion). Run it if you want to tune those; otherwise nothing is required:
|
|
127
139
|
|
|
128
140
|
```bash
|
|
129
|
-
gtd init #
|
|
141
|
+
gtd init # optional — seeds testCommand + a formatting suggestion
|
|
130
142
|
```
|
|
131
143
|
|
|
132
|
-
`gtd init` (no argument) writes a `.gtdrc.json` for the single bundled
|
|
133
|
-
**unified** template (its agent prompts extracted to editable `gtd-prompts/*.md`
|
|
134
|
-
files the config references). The template forks on which steering file you
|
|
135
|
-
create: `.gtd/TODO.md` starts the **simple flow** (a `planning` ⇄ `plan-review`
|
|
136
|
-
plan-iteration loop, direct `building`, a `checking`/`fixing` loop), while
|
|
137
|
-
`.gtd/REQUIREMENTS.md` starts the **advanced flow** (two-phase grilling ⇄
|
|
138
|
-
grilling-answer / architecting ⇄ architecting-answer / decompose / picking /
|
|
139
|
-
per-package build with an agentic spec-review gate). Both converge on the same
|
|
140
|
-
`reviewing` → `await-review` tail, and a full sign-off squashes the whole cycle
|
|
141
|
-
into one commit (see
|
|
142
|
-
[STATES.md §10](../STATES.md#10-the-bundled-workflow-templates)). Review and
|
|
143
|
-
commit the generated `.gtdrc.json` (and its `gtd-prompts/` directory), then
|
|
144
|
-
continue from a settled `idle` boundary. **Note:** a repo relying on earlier
|
|
145
|
-
gtd's auto-created `.gtdrc.json` `$schema` stub (which carried no `workflow:`)
|
|
146
|
-
will now fail until you `gtd init` — the stub alone is no longer enough.
|
|
147
|
-
|
|
148
144
|
A repo that customized v2's `workflow:` key (actors, gates, guard vocabulary,
|
|
149
145
|
ladders) needs to rewrite it from scratch in the v3 schema — see
|
|
150
146
|
[Configuration](configuration.md) for the schema and a complete worked example.
|