@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.
@@ -0,0 +1,125 @@
1
+ # Upgrading to v3 (BREAKING CHANGE)
2
+
3
+ ## v3 is a clean break
4
+
5
+ v3 ("the pattern machine") deletes the entire v2 definition model — gates, guard
6
+ functions, actor kinds, interrupt/fallback ladders, capture rules, turn and
7
+ routing rules, `Gtd-Counters` trailers, conflicts, the review checkout window —
8
+ and replaces it with the much smaller pattern machine described in
9
+ [STATES.md](../STATES.md): named states, each with one content kind and an
10
+ ordered map of change-patterns to next states.
11
+
12
+ **All pre-v3 history is unrecognized and resolves to the initial state, by
13
+ design — v1 and v2 subjects alike.** v3's `resolveState`
14
+ (`src/PatternMachine.ts`) only recognizes its own `gtd(<actor>): <state>`
15
+ subject naming a state and an actor the active workflow currently declares;
16
+ everything else — a v1 `gtd: grilling`, a v2 `gtd(agent): building`, a plain
17
+ `chore: …` commit, anything from a foreign repo — parses as unrecognized and
18
+ lands at the workflow's initial state (`idle` in the bundled default). There is
19
+ no special-casing for "this looks like an old gtd commit": the mechanism is
20
+ exactly the same one that already made v1 history inert to v2, and v2 history
21
+ inert to a differently-configured workflow — v3 just applies it uniformly to all
22
+ prior history instead of drawing a v1/v2 line.
23
+
24
+ **Finish or squash any in-flight cycle first.** A repo mid-cycle on v1 or v2 has
25
+ no v3-shaped commit backing its steering files; upgrading mid-cycle lands cold
26
+ at the initial state with those files still pending, which the new workflow's
27
+ `on` patterns will classify as ordinary pending changes, not as the phase they
28
+ used to represent. Finish the cycle (or squash it) on the old binary first, or
29
+ manually clean up the steering files and commit a plain boundary, before
30
+ upgrading.
31
+
32
+ ## What died
33
+
34
+ - **Counters.** `Gtd-Counters` trailers, `fixAttemptCap`/`reviewThreshold`
35
+ config keys, and the counter-stamp machinery are gone. The only budget
36
+ affordance left is a state's own `retry: { max, otherwise }`
37
+ (§[STATES.md](../STATES.md#7-retry)) — a plain per-process entry cap
38
+ redirected at write time, with no trailer to read back.
39
+ - **`.gtdrc` keys.** The old `testCommand`, `fixAttemptCap`, `reviewThreshold`,
40
+ `agenticReview`, `squash`, `learning`, `decisionLog`, and `models` keys are
41
+ all gone — `workflow:` and `vars:` are the only two blessed keys (see
42
+ [Configuration](configuration.md)). A check's command now lives inline in its
43
+ own `script:` content, reading a workflow-declared `it.vars` entry (the
44
+ bundled default's `testCommand`, overridable via the top-level `vars:` key or
45
+ a `GTD_VAR_testCommand` environment variable — see
46
+ [Configuration's "Variables"](configuration.md#variables)) rather than a
47
+ blessed `testCommand` config key; squashing is a `commit:` state instead of a
48
+ boolean flag; there is no learning phase, no decision log, and no model
49
+ tiering — a workflow author is free to build any of that shape back with
50
+ states of their own, but gtd no longer bakes it in.
51
+ - **The review checkout window.** v2 rewound HEAD/index to the review base while
52
+ a human review rested, so editors would show the diff directly. Deleted in v3
53
+ (may return later as an explicit state property — not in scope now).
54
+ - **`forceApprove`, content-inspection verdicts.** FEEDBACK.md emptiness,
55
+ checkbox-only REVIEW.md diffs, and doc-structure validation are gone as ENGINE
56
+ mechanisms — verdicts are now expressed purely by which file a turn writes or
57
+ deletes, matched by an ordinary `on` pattern. The bundled default workflow's
58
+ own two validation loops (`todo-validating`/`review-validating`/
59
+ `review-deciding` — see
60
+ [docs/design/steering-file-loops.md](design/steering-file-loops.md)) rebuild
61
+ checkbox-review and doc-structure verdicts as ordinary WORKFLOW data
62
+ (`script`-content states + `on` patterns), not an engine hook: `D REVIEW.md` =
63
+ approve, `M REVIEW.md` = route to the deterministic decider, in the bundled
64
+ default.
65
+ - **`gtd questions` / `gtd changesets` / `gtd review <target>`.** Gone; the v3
66
+ command surface is `step` / `next` / `run` / `status` / `format` / `lsp` (see
67
+ [CLI reference](cli.md)).
68
+ - **Model tiers, the decision log.** No `models` config key, no `Gtd-Decisions`
69
+ trailer scan, no grilling/architecting "prior decisions" context assembled
70
+ from history.
71
+ - **LSP.** Deleted at the v3 rewrite, then resurrected file-format-keyed rather
72
+ than state-keyed (`gtd lsp` — see
73
+ [Development](development.md#the-lsp-server)). The `gtd.openSteeringFile`
74
+ command is BACK (see
75
+ [docs/design/state-file-association.md](design/state-file-association.md)) —
76
+ config-driven rather than the v2 hardcoded state→file map: any state may
77
+ declare a `file:` (an Eta template) and a `mode:` (`qa`/`review`, the file's
78
+ format), the LSP reads that same config the CLI does to build its path→mode
79
+ dispatch, and `gtd.openSteeringFile` resolves the current state and shows its
80
+ `file:`. No mapping declared at all (the bundled default's predecessor shape,
81
+ or any workflow with no `file:`/`mode:`) falls back to basename dispatch
82
+ (`TODO.md`/`REVIEW.md`), same as before this addition.
83
+
84
+ ## How to adopt
85
+
86
+ `workflow:` is optional — with no config at all, the bundled default workflow
87
+ applies: a single-shot `grilling` plan, direct `building`, a `checking`/`fixing`
88
+ loop, and a direct-diff `await-review` that rests the cycle back at `idle` on
89
+ approval — no squash; every turn commit stays in history for you to squash
90
+ however you like, or not at all (see
91
+ [STATES.md §10](../STATES.md#10-the-bundled-default-workflow)) — expressed as
92
+ data rather than baked into the engine. The fuller grilling ⇄ grilling-answer /
93
+ architecting ⇄ architecting-answer / decompose / picking / reviewing shape v2
94
+ shipped — including a squash finale — is preserved as a copy-paste `.gtdrc`
95
+ example at [docs/examples/advanced-workflow.md](examples/advanced-workflow.md)
96
+ rather than the bundled default. Nothing to do for a repo that's happy with the
97
+ default shape beyond a normal `npm install -g @pmelab/gtd` upgrade, from a
98
+ settled `idle` boundary.
99
+
100
+ A repo that customized v2's `workflow:` key (actors, gates, guard vocabulary,
101
+ ladders) needs to rewrite it from scratch in the v3 schema — see
102
+ [Configuration](configuration.md) for the schema and a complete worked example.
103
+ There is no automatic migration: the two vocabularies don't map field-for-field
104
+ (guards become patterns, capture rules become `on` targets, counters become
105
+ `retry`), so a v2 `workflow:` config is simply invalid v3 config and fails
106
+ loudly at load time rather than silently misinterpreting.
107
+
108
+ **Re-copy the loop skill.** If you vendor `skills/loop/` into a consuming repo
109
+ or agent harness, upgrading the `gtd` binary also means re-copying that skill
110
+ from this release.
111
+
112
+ ## Prior breaking change: the v1 → v2 label grammar (historical)
113
+
114
+ v2 replaced v1's undifferentiated turn labels with six labels carrying the
115
+ branch outcome at capture time, moved steering files under `.gtd/`, and
116
+ introduced `Gtd-Counters` commit trailers. All of that is itself now superseded
117
+ by v3's clean break above — a v1 or v2 repo upgrades to v3 the same way
118
+ (finish/squash any in-flight cycle, then upgrade from a settled boundary);
119
+ there's no reason to upgrade v1 → v2 → v3 in two hops.
120
+
121
+ For maintainers: this repo releases via `semantic-release` reading Conventional
122
+ Commits, and needs **no config change** for a major bump — but the release
123
+ commit/PR **must carry a `BREAKING CHANGE:` footer** (or a `!` after the type)
124
+ for `@semantic-release/commit-analyzer` to compute the next major version rather
125
+ than a minor/patch bump.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmelab/gtd",
3
- "version": "2.8.0",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "description": "Git-aware CLI that emits the next prompt for an autonomous coding agent based on the current repository state",
6
6
  "bin": {
@@ -84,6 +84,6 @@
84
84
  "eta": "^4.6.0",
85
85
  "prettier": "^3.8.1",
86
86
  "vscode-languageserver": "^10.1.0",
87
- "vscode-languageserver-textdocument": "^1.0.12"
87
+ "vscode-languageserver-textdocument": "^1.0.13"
88
88
  }
89
89
  }
package/schema.json CHANGED
@@ -1,82 +1,106 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$defs": {
4
- "Int": {
5
- "type": "integer",
6
- "description": "an integer",
7
- "title": "int"
8
- }
9
- },
10
3
  "type": "object",
11
4
  "required": [],
12
5
  "properties": {
13
- "testCommand": {
14
- "type": "string"
15
- },
16
- "models": {
6
+ "workflow": {
17
7
  "type": "object",
18
- "required": [],
8
+ "description": "The whole machine definition: named states (plus the workflow's own vars: defaults). Compiled and validated by gtd at load time; content strings starting with ./ or ../ are file references inlined from the config file's directory.",
9
+ "additionalProperties": false,
10
+ "required": ["states"],
19
11
  "properties": {
20
- "planning": {
21
- "type": "string"
22
- },
23
- "execution": {
24
- "type": "string"
12
+ "vars": {
13
+ "type": "object",
14
+ "description": "Flat name -> scalar map merged into every template's it.vars. Scalars are coerced to strings.",
15
+ "additionalProperties": {
16
+ "type": ["string", "number", "boolean"]
17
+ }
25
18
  },
26
19
  "states": {
27
20
  "type": "object",
28
- "required": [],
29
- "properties": {
30
- "decompose": {
31
- "type": "string"
32
- },
33
- "grilling": {
34
- "type": "string"
35
- },
36
- "architecting": {
37
- "type": "string"
38
- },
39
- "building": {
40
- "type": "string"
41
- },
42
- "fixing": {
43
- "type": "string"
44
- },
45
- "agentic-review": {
46
- "type": "string"
47
- },
48
- "clean": {
49
- "type": "string"
21
+ "description": "The workflow's named states. At least one; exactly one with initial: true.",
22
+ "minProperties": 1,
23
+ "additionalProperties": {
24
+ "type": "object",
25
+ "description": "One workflow state. Declare exactly one content kind (script/prompt/message/commit). A commit state is final: no actor, no on.",
26
+ "additionalProperties": false,
27
+ "properties": {
28
+ "actor": {
29
+ "type": "string",
30
+ "description": "Who acts at this state. Required on every non-commit state; forbidden on a commit state."
31
+ },
32
+ "script": {
33
+ "type": "string",
34
+ "description": "Content kind: a shell script (Eta template). `gtd run` executes it verbatim via bash, then steps this state's actor."
35
+ },
36
+ "prompt": {
37
+ "type": "string",
38
+ "description": "Content kind: an agent prompt (Eta template), emitted by `gtd next`."
39
+ },
40
+ "message": {
41
+ "type": "string",
42
+ "description": "Content kind: a human-facing message (Eta template), emitted by `gtd next`."
43
+ },
44
+ "commit": {
45
+ "type": "string",
46
+ "description": "Content kind: entering this state ends the process by squashing it into one commit with this message (Eta template). Final — no actor, no on."
47
+ },
48
+ "on": {
49
+ "type": "object",
50
+ "description": "Ordered map of change pattern -> target state. Patterns: \"C\" (clean tree) or \"<A|M|D|*> <glob>\" over the pending diff; first declared match wins. Every target must name a defined state, and every non-initial state must be reachable through these edges (or a retry.otherwise).",
51
+ "additionalProperties": {
52
+ "type": "string"
53
+ }
54
+ },
55
+ "initial": {
56
+ "type": "boolean",
57
+ "description": "Exactly one state in the workflow must declare initial: true (and it must not be a commit state)."
58
+ },
59
+ "retry": {
60
+ "type": "object",
61
+ "description": "Redirect transitions INTO this state once it has been entered `max` times in the current process.",
62
+ "additionalProperties": false,
63
+ "required": ["max", "otherwise"],
64
+ "properties": {
65
+ "max": {
66
+ "type": "integer",
67
+ "minimum": 0,
68
+ "description": "Entries allowed this process before redirecting."
69
+ },
70
+ "otherwise": {
71
+ "type": "string",
72
+ "description": "Defined state to redirect to once over the cap."
73
+ }
74
+ }
75
+ },
76
+ "model": {
77
+ "type": "string",
78
+ "description": "Opaque harness hint passed through `gtd next --json`/`gtd status --json` (e.g. \"smart\"). Never interpreted by gtd. Forbidden on a commit state."
79
+ },
80
+ "file": {
81
+ "type": "string",
82
+ "description": "The state's steering file: an Eta template naming the file a human/editor should look at while the machine rests here. Forbidden on a commit state."
83
+ },
84
+ "mode": {
85
+ "type": "string",
86
+ "enum": ["qa", "review"],
87
+ "description": "The steering file's format, dispatched on by the LSP. Requires a sibling `file:`. Forbidden on a commit state."
88
+ }
50
89
  }
51
- },
52
- "additionalProperties": false
90
+ }
53
91
  }
54
- },
55
- "additionalProperties": false
92
+ }
56
93
  },
57
- "agenticReview": {
58
- "type": "boolean"
59
- },
60
- "squash": {
61
- "type": "boolean"
62
- },
63
- "learning": {
64
- "type": "boolean"
65
- },
66
- "decisionLog": {
67
- "type": "boolean"
68
- },
69
- "fixAttemptCap": {
70
- "$ref": "#/$defs/Int",
71
- "description": "a non-negative number",
72
- "title": "greaterThanOrEqualTo(0)",
73
- "minimum": 0
94
+ "vars": {
95
+ "type": "object",
96
+ "description": "Flat name -> scalar map merged into every template's it.vars. Scalars are coerced to strings.",
97
+ "additionalProperties": {
98
+ "type": ["string", "number", "boolean"]
99
+ }
74
100
  },
75
- "reviewThreshold": {
76
- "$ref": "#/$defs/Int",
77
- "description": "a number greater than or equal to 1",
78
- "title": "greaterThanOrEqualTo(1)",
79
- "minimum": 1
101
+ "$schema": {
102
+ "type": "string",
103
+ "description": "Editor-only pointer at this schema. Stripped by gtd before validation."
80
104
  }
81
105
  },
82
106
  "additionalProperties": false
@@ -1,45 +0,0 @@
1
- # Upgrading from v1 (BREAKING CHANGE)
2
-
3
- v2 ships as a **major** semantic-release bump (`2.0.0`) so the binary and the
4
- loop-driving text ([docs/loop.md](loop.md), `skills/loop/SKILL.md`) can never
5
- skew against each other. There is **no backward compatibility with the v1
6
- command surface**: the single mutating `gtd` command, marker/sentinel files, the
7
- `autoAdvance` JSON field, and the `gtd: transport` handoff commit are all gone.
8
- `gtd` bare now errors rather than driving a loop; use `gtd step-agent` /
9
- `gtd next` / `gtd step` instead.
10
-
11
- **Commit-history compatibility is one-way.** Any repo with v1-taxonomy history
12
- in it (`gtd: new task`, `gtd: grilling`, `gtd: transport`, a bare
13
- `gtd: reviewing` with no hash, …) upgrades cleanly: those subjects fall outside
14
- v2's closed turn/routing grammar and parse as inert **boundary commits** — they
15
- are never mistaken for v2 workflow state and never error.
16
-
17
- **Finish or clean up any in-flight v1 cycle first.** If a repo has an
18
- **in-progress** v1 cycle — steering files present (root-level `TODO.md`,
19
- `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, or `.gtd/`) whose HEAD carries v1-only
20
- commit subjects — the v2 binary does not know how to resume it: v1 steering
21
- files have no v2 turn commit backing them, so a cold v2 invocation on that tree
22
- can land in an unrecognized state. Either finish the v1 cycle to a clean
23
- boundary with your existing v1 binary before upgrading, or manually clean up
24
- (remove the steering files / `.gtd/`, commit the result) so the upgrade starts
25
- from a plain boundary HEAD.
26
-
27
- **Steering files moved into `.gtd/`.** Earlier v2 builds kept `TODO.md`,
28
- `REVIEW.md`, `FEEDBACK.md`, `ERRORS.md`, `HEALTH.md`, and `SQUASH_MSG.md` at the
29
- repository root; they now live under `.gtd/`. Upgrade at a clean boundary (idle,
30
- post-squash): a repo at rest needs nothing. Mid-cycle repos should either finish
31
- the cycle on the old build first or move the root-level steering files into
32
- `.gtd/` by hand and commit. History classification is backward-compatible — the
33
- counter folds recognize both the old root paths and the new `.gtd/` paths in
34
- existing commits.
35
-
36
- **Re-copy the loop skill.** If you vendor `skills/loop/` into a consuming repo
37
- or agent harness, upgrading the `gtd` binary also means re-copying that skill
38
- from this release — the v1 skill text still describes the old single-command
39
- loop and will drive the new binary incorrectly.
40
-
41
- For maintainers: this repo releases via `semantic-release` reading Conventional
42
- Commits, and needs **no config change** for a major bump — but the release
43
- commit/PR **must carry a `BREAKING CHANGE:` footer** (or a `!` after the type)
44
- for `@semantic-release/commit-analyzer` to compute `2.0.0` rather than a
45
- minor/patch bump.