@pmelab/gtd 2.8.0 → 3.1.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 +61 -40
- package/bin/gtd-loop +43 -23
- package/dist/gtd.bundle.mjs +2511 -3481
- package/docs/cli.md +222 -281
- package/docs/configuration.md +350 -71
- package/docs/design/configurable-state-machine.md +1439 -0
- package/docs/design/delta-purity-plan.md +283 -0
- package/docs/design/pattern-machine-plan.md +164 -0
- package/docs/design/scripted-actor.md +289 -0
- package/docs/design/state-file-association.md +112 -0
- package/docs/design/state-machine-validation.md +437 -0
- package/docs/design/steering-file-loops.md +164 -0
- package/docs/design/work-packages.md +194 -0
- package/docs/development.md +55 -36
- package/docs/examples/advanced-workflow.md +428 -0
- package/docs/loop.md +60 -60
- package/docs/upgrading.md +125 -0
- package/package.json +2 -2
- package/schema.json +89 -65
- package/docs/upgrading-from-v1.md +0 -45
- package/docs/workflow.md +0 -428
package/docs/cli.md
CHANGED
|
@@ -4,14 +4,19 @@
|
|
|
4
4
|
Usage: gtd [command] [options]
|
|
5
5
|
|
|
6
6
|
Commands:
|
|
7
|
-
step
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
step <actor> Authenticate as <actor>, match the resolved rest's
|
|
8
|
+
declared patterns against the pending changes, and commit
|
|
9
|
+
(or squash) the one resulting transition
|
|
10
|
+
next Print the resolved rest's rendered script/prompt/message
|
|
11
|
+
(no mutation)
|
|
12
|
+
run Execute the resolved rest's emitted script, then step its
|
|
13
|
+
actor (the built-in script driver)
|
|
14
|
+
status Print the resolved rest's state/actor and which declared
|
|
15
|
+
pattern (if any) each pending change matches (no mutation)
|
|
16
|
+
mermaid Print the active workflow's shape as Mermaid
|
|
17
|
+
stateDiagram-v2 source (no mutation)
|
|
14
18
|
format <file> Format a markdown file in place
|
|
19
|
+
lsp Start the LSP server for .gtd/ steering files (stdio)
|
|
15
20
|
|
|
16
21
|
Options:
|
|
17
22
|
--json Output structured JSON instead of plain text
|
|
@@ -23,334 +28,270 @@ Options:
|
|
|
23
28
|
repository-state work — they run outside a repo and in any repo state. Bare
|
|
24
29
|
`gtd` (no subcommand) is a usage error: it prints the help text and exits 1
|
|
25
30
|
without touching the repository. Every other command must be run from the
|
|
26
|
-
**repository root** — gtd derives
|
|
27
|
-
to cwd, so it refuses with a clear error if invoked from a
|
|
31
|
+
**repository root** — gtd derives the workflow, pending changes, and process
|
|
32
|
+
history relative to cwd, so it refuses with a clear error if invoked from a
|
|
33
|
+
subdirectory.
|
|
28
34
|
|
|
29
35
|
`--json` is the only long option. Any other `--` option (including a typo like
|
|
30
36
|
`--jsn`) is rejected with a usage error rather than silently ignored, so a
|
|
31
37
|
mistyped flag can never degrade a JSON caller to plain-text mode.
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
**Idempotence.** Re-running the same command again once the tree is settled at a
|
|
56
|
-
rest authors **zero** new commits. It exits 0 while the rest still awaits that
|
|
57
|
-
command's actor (an inert empty agent turn, the idle health check); once the
|
|
58
|
-
rest awaits the _other_ actor, the re-run is an out-of-turn refusal — still zero
|
|
59
|
-
commits, but non-zero exit.
|
|
60
|
-
|
|
61
|
-
**Out-of-turn refusal.** Human and agent turns are strictly separated: the wrong
|
|
62
|
-
mutator always errors, at every state, on clean and dirty trees alike.
|
|
63
|
-
`gtd step-agent` while a human turn is awaited refuses with
|
|
64
|
-
`"<state> awaits a human turn — run \`gtd step\`"`; `gtd
|
|
65
|
-
step`while an agent turn is awaited refuses with`"<state> awaits an agent turn —
|
|
66
|
-
run \`gtd
|
|
67
|
-
step-agent\`"`— exit non-zero, zero commits either way. Human edits made while the agent is awaited (e.g. amendment notes in`.gtd/`package files after the`gtd:
|
|
68
|
-
planning` commit lands) stay pending in the working tree and ride along as input
|
|
69
|
-
to the agent's next captured turn; left unamended, the build proceeds.
|
|
70
|
-
|
|
71
|
-
**Red-test fixpoints exit 0.** A red test run below the fix-attempt cap (or the
|
|
72
|
-
health-fix cap) still writes its findings and commits — it is a normal,
|
|
73
|
-
successful step of the loop, not a failure of the `step`/`step-agent`
|
|
74
|
-
invocation. `step`/`step-agent` only exit non-zero for a genuine refusal or an
|
|
75
|
-
operational error (bad config, missing test binary, corrupted state).
|
|
76
|
-
|
|
77
|
-
**Output.** Plain mode prints one `committed: <subject>` line per commit this
|
|
78
|
-
invocation authored (oldest→newest), then a final `state: <state>` line:
|
|
39
|
+
## `gtd step <actor>`
|
|
40
|
+
|
|
41
|
+
Authenticates `<actor>` against the resolved rest and performs the ONE resulting
|
|
42
|
+
transition. Unlike v2, there is no fixpoint chain to drive: the pattern
|
|
43
|
+
machine's `on` edges are direct one-hop transitions, so a single invocation
|
|
44
|
+
authors at most one commit (a normal turn) or performs one squash
|
|
45
|
+
(§[STATES.md](../STATES.md#8-the-squash-lifecycle)) — never both, never a chain
|
|
46
|
+
of several. A caller that wants several transitions issues several invocations.
|
|
47
|
+
|
|
48
|
+
- **Out-of-turn refusal** — `<actor>` isn't the resolved state's declared actor:
|
|
49
|
+
exit non-zero, zero commits.
|
|
50
|
+
`gtd step <actor>: out of turn — "<state>" awaits <awaited-actor>`
|
|
51
|
+
- **No-match refusal** — the tree is dirty and no declared `on` pattern matches:
|
|
52
|
+
exit non-zero, zero commits, naming every declared pattern.
|
|
53
|
+
`gtd step <actor>: no declared pattern matches the pending changes at "<state>" — declared patterns: <p1>, <p2>, …`
|
|
54
|
+
- **No-op** — the tree is clean and the state declares no `C` pattern: exit
|
|
55
|
+
**0**, zero commits. This is the default, silent case a loop driver relies on
|
|
56
|
+
(see [Driving the loop](loop.md)).
|
|
57
|
+
- **Commit/squash** — a pattern matched: exit 0, one commit (or one squash)
|
|
58
|
+
authored.
|
|
59
|
+
|
|
60
|
+
Plain-mode output is one line:
|
|
79
61
|
|
|
80
62
|
```
|
|
81
63
|
committed: gtd(human): grilling
|
|
82
|
-
committed: gtd: architecting
|
|
83
|
-
state: architecting
|
|
84
64
|
```
|
|
85
65
|
|
|
86
|
-
|
|
87
|
-
[JSON schemas](#json-schemas)).
|
|
88
|
-
|
|
89
|
-
## `gtd next`
|
|
90
|
-
|
|
91
|
-
Pure prompt emitter — it **never mutates** the repository. It reports whichever
|
|
92
|
-
actor is currently awaited and, if the tree is at a genuine rest, the full
|
|
93
|
-
prompt for that actor.
|
|
94
|
-
|
|
95
|
-
**Purity.** No commits, no file writes, no test runs — `gtd next` only gathers
|
|
96
|
-
and resolves.
|
|
97
|
-
|
|
98
|
-
**Dirty-tree refusal.** If the working tree has pending changes outside the
|
|
99
|
-
steering-file set, `gtd next` refuses rather than guess at a prompt for a state
|
|
100
|
-
that hasn't been captured yet:
|
|
66
|
+
or, at a no-op:
|
|
101
67
|
|
|
102
68
|
```
|
|
103
|
-
|
|
69
|
+
nothing to do at "idle"
|
|
104
70
|
```
|
|
105
71
|
|
|
106
|
-
|
|
107
|
-
invocation would perform before reaching a rest — `gtd next` reports
|
|
108
|
-
`pending: true` with no prompt. Mid-chain bookkeeping is invoker-agnostic, so
|
|
109
|
-
either mutator resumes it; the report names the actor whose chain it is. In
|
|
110
|
-
plain mode an agent-driven checkpoint prints `"mid-chain checkpoint — run \`gtd
|
|
111
|
-
step-agent\` to continue, then run \`gtd next\`
|
|
112
|
-
again"`, a human-driven one prints `"mid-chain checkpoint — run \`gtd step\` to
|
|
113
|
-
continue"`.
|
|
72
|
+
`--json` emits `{state, subject}` — `subject` is `null` at a no-op:
|
|
114
73
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```
|
|
119
|
-
Finish your turn by running `gtd step-agent`. Then run `gtd next` and follow
|
|
120
|
-
its output — repeat this cycle as long as the output is addressed to you (the
|
|
121
|
-
agent); when it awaits the human, stop and hand off.
|
|
74
|
+
```json
|
|
75
|
+
{ "state": "grilling", "subject": "gtd(human): grilling" }
|
|
122
76
|
```
|
|
123
77
|
|
|
124
|
-
|
|
125
|
-
it is what lets a plain-text agent chain multiple iterations (e.g. successive
|
|
126
|
-
test/fix cycles) without an external driver, until a human gate is reached.
|
|
127
|
-
Human-actor prompts carry no tail. `--json` output never embeds the tail into
|
|
128
|
-
`prompt` either — the structured `actor` field (see
|
|
129
|
-
[JSON schemas](#json-schemas) below) carries the same information: `"agent"`
|
|
130
|
-
means another agent round, `"human"` means stop and hand off.
|
|
131
|
-
|
|
132
|
-
## `gtd status`
|
|
78
|
+
## `gtd next [--json]`
|
|
133
79
|
|
|
134
|
-
Pure
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
80
|
+
Pure emitter of the resolved rest's rendered content — it **never mutates** the
|
|
81
|
+
repository (no commits, no file writes, no script execution). Resolves HEAD
|
|
82
|
+
exactly like `gtd step`, renders that state's declared
|
|
83
|
+
`script`/`prompt`/`message` template, and prints it. `kind` is never `"commit"`
|
|
84
|
+
here: resolution never rests at a commit state (entering one always ends the
|
|
85
|
+
process in the same step that entered it — see
|
|
86
|
+
[STATES.md §5](../STATES.md#5-resolution)).
|
|
138
87
|
|
|
139
|
-
|
|
88
|
+
Plain mode prints the rendered content verbatim (with exactly one trailing
|
|
89
|
+
newline) — never the `model`/`file`/`mode` hints, which are JSON-only. `--json`
|
|
90
|
+
emits `{state, actor, kind, content, model?, file?, mode?}`:
|
|
140
91
|
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"state": "building",
|
|
95
|
+
"actor": "agent",
|
|
96
|
+
"kind": "prompt",
|
|
97
|
+
"content": "You are an autonomous coding agent. ..."
|
|
98
|
+
}
|
|
146
99
|
```
|
|
147
100
|
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
|
|
154
|
-
|
|
101
|
+
- `state` — the resolved state.
|
|
102
|
+
- `actor` — the state's declared actor.
|
|
103
|
+
- `kind` — `"script"` | `"prompt"` | `"message"` — the dispatch key a driver
|
|
104
|
+
switches on (see [Driving the loop](loop.md)).
|
|
105
|
+
- `content` — the fully rendered template.
|
|
106
|
+
- `model` — the state's opaque `model:` hint, RENDERED through the same template
|
|
107
|
+
context as `content` (see
|
|
108
|
+
[Configuration](configuration.md#model--the-opaque-harness-hint-template-rendered)),
|
|
109
|
+
present only when the state declares one; **omitted entirely** (never `null`)
|
|
110
|
+
when unset.
|
|
111
|
+
- `file` — the state's declared steering file, RENDERED the same way; `mode` —
|
|
112
|
+
its format, verbatim (`"qa"` | `"review"`) (see
|
|
113
|
+
[Configuration](configuration.md#filemode--the-steering-file-association)).
|
|
114
|
+
Both present only when the state declares them; **omitted entirely** (never
|
|
115
|
+
`null`) otherwise.
|
|
116
|
+
|
|
117
|
+
## `gtd run`
|
|
118
|
+
|
|
119
|
+
The built-in driver for a `script`-content rest — the **only** place gtd itself
|
|
120
|
+
spawns a subprocess. Renders the resolved rest exactly like `gtd next`, executes
|
|
121
|
+
its content verbatim via `bash -c` (foreground, inherited stdio, exit code
|
|
122
|
+
deliberately ignored — a check script encodes its outcome in the tree, e.g.
|
|
123
|
+
writing a findings file, never in its exit status), then runs `gtd step <actor>`
|
|
124
|
+
for that state's own actor to capture the outcome in one command. Refuses (exit
|
|
125
|
+
non-zero, no execution, no step) when the resolved rest isn't a script:
|
|
155
126
|
|
|
156
|
-
## `gtd review <target>`
|
|
157
|
-
|
|
158
|
-
A pure mutator that **anchors, then exits** — it never prints a prompt itself.
|
|
159
|
-
Use it to start an ad-hoc human review against an explicit git ref or branch,
|
|
160
|
-
independent of the automatic review base the workflow otherwise computes.
|
|
161
|
-
|
|
162
|
-
1. Refuses on a dirty tree.
|
|
163
|
-
2. Resolves `<target>` via merge-base semantics and computes the diff HEAD adds
|
|
164
|
-
over `merge-base(<target>, HEAD)`.
|
|
165
|
-
3. Refuses if that diff is empty after filtering ("nothing to review").
|
|
166
|
-
4. Authors exactly one commit: `gtd: reviewing <full-hash-of-the-base>`.
|
|
167
|
-
5. Prints a short confirmation pointing at `gtd next` — it does **not** print
|
|
168
|
-
the review prompt itself.
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
gtd review main
|
|
172
|
-
# anchored review at <hash> — run `gtd next` to get the review prompt
|
|
173
|
-
gtd next --json
|
|
174
|
-
# {"actor":"agent", ...} — the review-record prompt scoped to that anchor
|
|
175
127
|
```
|
|
176
|
-
|
|
177
|
-
Errors (all exit 1, message on stderr):
|
|
178
|
-
|
|
179
|
-
- Missing target: `gtd review: missing target argument`
|
|
180
|
-
- Extra arguments:
|
|
181
|
-
`gtd review: too many arguments — expected one target, got: …`
|
|
182
|
-
- Unresolvable ref: `gtd review: cannot resolve ref '<target>': <error message>`
|
|
183
|
-
- Empty diff:
|
|
184
|
-
`gtd review: nothing to review (<target> diff is empty after filtering)`
|
|
185
|
-
|
|
186
|
-
## `gtd questions` / `gtd changesets`
|
|
187
|
-
|
|
188
|
-
Pure, read-only reporters — no dirty-tree check, no mutation — that parse the
|
|
189
|
-
structured content out of the active grilling/architecting and review documents,
|
|
190
|
-
for a future UI:
|
|
191
|
-
|
|
192
|
-
- **`gtd questions`** reads whichever of `.gtd/TODO.md` / `.gtd/ARCHITECTURE.md`
|
|
193
|
-
is present and reports its `## Open Questions` list (see
|
|
194
|
-
[Structured grilling/architecting and review files](workflow.md#structured-grillingarchitecting-and-review-files)).
|
|
195
|
-
Reports an empty list when neither file exists.
|
|
196
|
-
- **`gtd changesets`** reads `.gtd/REVIEW.md`, if present, and reports its
|
|
197
|
-
chunks/file-pointer list. Reports an empty list when the file doesn't exist.
|
|
198
|
-
|
|
199
|
-
Both take no arguments and always exit 0 — a malformed file is reported via the
|
|
200
|
-
`errors` field/lines rather than failing the command (the same diagnosis
|
|
201
|
-
`gtd step-agent` would refuse the agent's next turn capture with).
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
gtd questions --json
|
|
205
|
-
# {"file":".gtd/TODO.md","questions":[{"question":"Which operations?","status":"suggested","text":"add and subtract."}],"errors":[]}
|
|
206
|
-
gtd changesets --json
|
|
207
|
-
# {"file":".gtd/REVIEW.md","shortHash":"abc1234","fullHash":"abc1234...","changesets":[...],"errors":[]}
|
|
128
|
+
gtd run: "<state>" awaits a <kind> from "<actor>" — nothing scripted to run
|
|
208
129
|
```
|
|
209
130
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
`printWidth: 80`, `proseWrap: "always"`), ignoring the host repo's own
|
|
214
|
-
`.prettierrc` so `.gtd/TODO.md`/`.gtd/REVIEW.md` stay consistently formatted
|
|
215
|
-
regardless of the host project's toolchain. Rejects `--json` (exit 1,
|
|
216
|
-
`gtd format does not accept --json`) — it is a plain file operation, not a v2
|
|
217
|
-
state command.
|
|
218
|
-
|
|
219
|
-
Errors (all exit 1, message on stderr):
|
|
220
|
-
|
|
221
|
-
- Missing path: `gtd format: missing file path argument`
|
|
222
|
-
- Extra arguments: `gtd format: too many arguments — expected one path, got: …`
|
|
223
|
-
- Non-markdown file:
|
|
224
|
-
`gtd format: <file> is not a markdown file (expected .md or .markdown)`
|
|
225
|
-
- File not found: `gtd: skipped formatting <file>: not found`
|
|
226
|
-
|
|
227
|
-
## JSON schemas
|
|
131
|
+
Reports the same `{state, subject}` (or `committed: …` / `nothing to do at "…"`)
|
|
132
|
+
as `gtd step` for the capturing step it performs. Takes no arguments — extra
|
|
133
|
+
positional args are rejected.
|
|
228
134
|
|
|
229
|
-
|
|
230
|
-
or `changesets` for machine-readable single-line JSON output instead of plain
|
|
231
|
-
text.
|
|
135
|
+
## `gtd status [--json]`
|
|
232
136
|
|
|
233
|
-
|
|
137
|
+
Pure, read-only dry-run reporter — the same resolution `gtd next` performs, but
|
|
138
|
+
reporting the resolved state/actor and, for every pending change, which declared
|
|
139
|
+
`on` pattern (if any) matches it — no mutation, and no CONTENT rendering (the
|
|
140
|
+
`script`/`prompt`/`message`/`commit` template is never rendered here, unlike
|
|
141
|
+
`gtd next`). It DOES render the resolved state's `model:`/`file:` hints (if
|
|
142
|
+
declared) through the same `it.vars`-carrying template context `gtd next` uses —
|
|
143
|
+
see
|
|
144
|
+
[Configuration](configuration.md#model--the-opaque-harness-hint-template-rendered)
|
|
145
|
+
— so a templated `model:`/`file:` failing to render fails `gtd status` too,
|
|
146
|
+
exactly like it would fail `gtd next`.
|
|
234
147
|
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
148
|
+
```
|
|
149
|
+
State: working
|
|
150
|
+
Awaits: agent
|
|
151
|
+
Pending:
|
|
152
|
+
A DONE.md -> A DONE.md
|
|
153
|
+
A scratch.txt -> (no match)
|
|
241
154
|
```
|
|
242
155
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
156
|
+
or, on a clean tree: `Pending: (clean)`. A `Model: <value>` line appears right
|
|
157
|
+
after `Awaits:` when the resolved state declares a `model:` hint, and
|
|
158
|
+
`File: <value>`/`Mode: <value>` lines appear after that (in that order) when
|
|
159
|
+
declared — each independently, only when set.
|
|
247
160
|
|
|
248
|
-
|
|
161
|
+
`--json` emits
|
|
162
|
+
`{state, actor, changes: [{status, path, pattern}], model?, file?, mode?}` —
|
|
163
|
+
`pattern` is `null` when no declared row matches that change; `model`/`file`/
|
|
164
|
+
`mode` are present only when the resolved state declares them (omitted entirely,
|
|
165
|
+
never `null`, otherwise):
|
|
249
166
|
|
|
250
167
|
```json
|
|
251
168
|
{
|
|
252
|
-
"state": "
|
|
169
|
+
"state": "working",
|
|
253
170
|
"actor": "agent",
|
|
254
|
-
"
|
|
255
|
-
|
|
171
|
+
"changes": [
|
|
172
|
+
{ "status": "A", "path": "DONE.md", "pattern": "A DONE.md" },
|
|
173
|
+
{ "status": "A", "path": "scratch.txt", "pattern": null }
|
|
174
|
+
]
|
|
256
175
|
}
|
|
257
176
|
```
|
|
258
177
|
|
|
259
|
-
|
|
260
|
-
- `actor` — `"human"` or `"agent"`: who owns the next move. This is the single
|
|
261
|
-
loop-driver signal: `"agent"` means proceed with another round — act on
|
|
262
|
-
`prompt` when present, then run `gtd step-agent`; at an agent-driven pending
|
|
263
|
-
checkpoint (`prompt` is `null`, nothing to act on) just run `gtd step-agent`.
|
|
264
|
-
`"human"` means halt and hand off (a human rest, whose prompt body already
|
|
265
|
-
tells the human what to do, or a human-driven pending checkpoint resumed by
|
|
266
|
-
`gtd step`).
|
|
267
|
-
- `pending` — `true` at a mid-chain HEAD (no prompt yet — resume with a mutator
|
|
268
|
-
first); `false` at a genuine rest.
|
|
269
|
-
- `prompt` — the full prompt markdown when `pending` is `false`, else `null`.
|
|
270
|
-
|
|
271
|
-
**`status`** — `{state, actor, predictedCommit, predictedState}`:
|
|
272
|
-
|
|
273
|
-
```json
|
|
274
|
-
{
|
|
275
|
-
"state": "grilling",
|
|
276
|
-
"actor": "human",
|
|
277
|
-
"predictedCommit": "gtd(human): grilling",
|
|
278
|
-
"predictedState": "grilling"
|
|
279
|
-
}
|
|
280
|
-
```
|
|
178
|
+
`gtd status` takes no arguments — extra positional args are rejected.
|
|
281
179
|
|
|
282
|
-
`
|
|
283
|
-
idle with a green health check).
|
|
180
|
+
## `gtd mermaid`
|
|
284
181
|
|
|
285
|
-
|
|
182
|
+
Pure emitter of the active workflow's **shape** — not the resolved rest — as
|
|
183
|
+
Mermaid [`stateDiagram-v2`](https://mermaid.js.org/syntax/stateDiagram.html)
|
|
184
|
+
source (see `src/Mermaid.ts`): one node per declared state, the `[*] -->`
|
|
185
|
+
initial-state marker, one edge per declared `on` row labeled with its raw
|
|
186
|
+
pattern string (same declaration order the engine itself evaluates), a `--> [*]`
|
|
187
|
+
edge for every commit state (final, no outgoing edges — see
|
|
188
|
+
[STATES.md §8](../STATES.md#8-the-squash-lifecycle)), and one `note right of`
|
|
189
|
+
per rest naming its actor, content kind, and retry cap (e.g.
|
|
190
|
+
`agent · prompt · retry 3→escalate`). No git, no HEAD resolution, no template
|
|
191
|
+
rendering — purely a function of the compiled `WorkflowDefinition`, so its
|
|
192
|
+
output is identical regardless of the current process/branch state.
|
|
286
193
|
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
194
|
+
```
|
|
195
|
+
$ gtd mermaid
|
|
196
|
+
stateDiagram-v2
|
|
197
|
+
state "idle" as idle
|
|
198
|
+
state "grilling" as grilling
|
|
199
|
+
...
|
|
200
|
+
[*] --> idle
|
|
201
|
+
idle --> grilling : * **
|
|
202
|
+
...
|
|
203
|
+
note right of idle : human · message
|
|
204
|
+
...
|
|
299
205
|
```
|
|
300
206
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
207
|
+
Pipe it straight into a `.md`/`.mmd` file, a GitHub issue/PR description, or any
|
|
208
|
+
Mermaid-aware renderer (GitHub, GitLab, VS Code, Obsidian, the
|
|
209
|
+
[Mermaid Live Editor](https://mermaid.live)) to get a diagram of a custom
|
|
210
|
+
`.gtdrc` `workflow:` with no hand-maintained docs required.
|
|
304
211
|
|
|
305
|
-
|
|
212
|
+
State names are aliased to Mermaid-safe identifiers (non-word characters fold to
|
|
213
|
+
`_`; a digit-led name gets an `s_` prefix) via a `state "<name>" as <alias>`
|
|
214
|
+
declaration up front, so a hyphenated name like `todo-validating` still displays
|
|
215
|
+
with its exact declared spelling. Rejects `--json` (exit 1,
|
|
216
|
+
`gtd mermaid does not accept --json`) — there is no structured shape to emit
|
|
217
|
+
beyond the Mermaid source itself — and takes no arguments (extra positional args
|
|
218
|
+
are rejected).
|
|
306
219
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
],
|
|
319
|
-
"errors": []
|
|
320
|
-
}
|
|
321
|
-
```
|
|
220
|
+
## `gtd format <file>`
|
|
221
|
+
|
|
222
|
+
Formats a markdown file in place with a bundled prettier (`parser: "markdown"`,
|
|
223
|
+
`printWidth: 80`, `proseWrap: "always"`), ignoring the host repo's own
|
|
224
|
+
`.prettierrc` so `.gtd/`-tracked files stay consistently formatted regardless of
|
|
225
|
+
the host project's toolchain. Rejects `--json` (exit 1,
|
|
226
|
+
`gtd format does not accept --json`) — it's a plain file operation, not a state
|
|
227
|
+
command.
|
|
228
|
+
|
|
229
|
+
Errors (all exit 1, message on stderr):
|
|
322
230
|
|
|
323
|
-
|
|
324
|
-
`
|
|
231
|
+
- Missing path: `gtd format: missing file path argument`
|
|
232
|
+
- Extra arguments: `gtd format: too many arguments — expected one path, got: …`
|
|
233
|
+
- Non-markdown file:
|
|
234
|
+
`gtd format: <file> is not a markdown file (expected .md or .markdown)`
|
|
235
|
+
- File not found: `gtd: skipped formatting <file>: not found`
|
|
325
236
|
|
|
326
|
-
|
|
327
|
-
|
|
237
|
+
## `gtd lsp`
|
|
238
|
+
|
|
239
|
+
Starts an LSP server over stdio for `.gtd/` steering files — document symbols
|
|
240
|
+
for a `qa`-mode file's open questions and a `review`-mode file's review
|
|
241
|
+
chunks/hunks, code actions to check/uncheck a hunk or a whole chunk, and
|
|
242
|
+
diagnostics publishing the same parser findings the bundled workflow's
|
|
243
|
+
`.gtd/FORMAT.md` validators produce (see `src/OpenQuestions.ts` /
|
|
244
|
+
`src/ReviewDoc.ts` and
|
|
245
|
+
[STATES.md §10](../STATES.md#10-the-bundled-default-workflow)).
|
|
246
|
+
|
|
247
|
+
**Config-driven** (see
|
|
248
|
+
[docs/design/state-file-association.md](design/state-file-association.md)): the
|
|
249
|
+
server locates the active gtd config the same way the CLI does, from the
|
|
250
|
+
`initialize` request's workspace root (falling back to the open document's own
|
|
251
|
+
directory), renders every state's `file:` into an absolute-path → `mode` map,
|
|
252
|
+
and dispatches on it — first declaring state wins a path conflict. A path the
|
|
253
|
+
map doesn't cover (or no config at all) falls back to the basename dispatch
|
|
254
|
+
(`TODO.md` → `qa`, `REVIEW.md` → `review`), so the server still works standalone
|
|
255
|
+
with no `.gtdrc` in sight. Also registers an `executeCommand`,
|
|
256
|
+
`gtd.openSteeringFile`: resolves the current state exactly like `gtd status`
|
|
257
|
+
(config + git HEAD) and asks the client to show its `file:`
|
|
258
|
+
(`window/showDocument`); a state with no `file:` gets an informational message
|
|
259
|
+
naming the state instead — bind it to an editor keybinding for a "jump to the
|
|
260
|
+
active steering file" command.
|
|
261
|
+
|
|
262
|
+
Dispatched before the repository-root guard and auto-init, like `gtd format`.
|
|
263
|
+
Rejects `--json` (exit 1, `gtd lsp does not accept --json`) and extra positional
|
|
264
|
+
arguments — it's a long-running server, not a state command. Runs until the
|
|
265
|
+
client disconnects (the LSP `exit` notification), then exits cleanly.
|
|
266
|
+
|
|
267
|
+
## Error envelope
|
|
268
|
+
|
|
269
|
+
Every command, in `--json` mode, reports a failure as a machine-readable
|
|
270
|
+
envelope on **stdout**, and still exits 1:
|
|
328
271
|
|
|
329
272
|
```json
|
|
330
273
|
{ "state": "error", "prompt": "<message>" }
|
|
331
274
|
```
|
|
332
275
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
auto-advance flag.
|
|
276
|
+
A human-readable `gtd: <message>` line is still written to **stderr** regardless
|
|
277
|
+
of `--json` — the envelope adds a structured stdout channel, it does not replace
|
|
278
|
+
the plain-text one.
|
|
337
279
|
|
|
338
280
|
## Repository requirements
|
|
339
281
|
|
|
340
|
-
- **Single writer, linear branch.**
|
|
341
|
-
|
|
342
|
-
— it degrades gracefully on the default branch rather than crashing, but do
|
|
343
|
-
not rely on merge commits mid-cycle.
|
|
282
|
+
- **Single writer, linear branch.** A process's history is walked via
|
|
283
|
+
**first-parent** commits only.
|
|
344
284
|
- **Test/build artifacts must be gitignored.** This is **load-bearing**, not a
|
|
345
|
-
style preference: every
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
285
|
+
style preference: every step decision detects "clean" via
|
|
286
|
+
`git diff --name-status HEAD` (tracked changes) unioned with
|
|
287
|
+
`git ls-files --others --exclude-standard` (untracked files), which silently
|
|
288
|
+
omits anything matched by `.gitignore`. If a `script` state's command (or the
|
|
289
|
+
build it triggers) writes tracked-but-untracked output — a `dist/`, a coverage
|
|
290
|
+
report, a log file — into the working tree, the tree never goes clean after a
|
|
291
|
+
green run, and the check's `"C"` pattern never fires. Gitignore every path
|
|
292
|
+
your scripts write before wiring gtd into a repo.
|
|
293
|
+
- **Repository root invocation.** Every state subcommand (`step`/`next`/`run`/
|
|
294
|
+
`status`/`mermaid`) must run from the git repository root — the workflow,
|
|
295
|
+
pending changes, and process history are resolved against the process cwd.
|
|
296
|
+
`--help`/`--version`, `format`, and `lsp` skip this guard entirely (and any
|
|
297
|
+
git/`.gtdrc` dependency along with it).
|