scrumrun 3.0.0 → 3.0.2
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/CHANGELOG.md +17 -0
- package/CORE.md +14 -12
- package/README.md +53 -31
- package/SPEC.md +4 -4
- package/bin/scrumrun.js +59 -35
- package/docs/COMMANDS.md +51 -35
- package/docs/DEMO.md +6 -6
- package/docs/ERROR-CODES.md +11 -11
- package/docs/QUICKSTART.md +14 -14
- package/docs/RELEASE-SCORECARD.md +1 -1
- package/docs/RELEASE.md +1 -1
- package/docs/SEMANTIC-MEMORY.md +3 -3
- package/docs/TROUBLESHOOTING.md +9 -9
- package/lib/commands/manifest.js +3 -3
- package/lib/commands/normalize-legacy.js +1 -1
- package/lib/commands/pretty-intake.js +2 -2
- package/lib/commands/render.js +8 -5
- package/lib/commands/repair.js +61 -8
- package/lib/errors.js +11 -11
- package/lib/runtime/briefing.js +2 -2
- package/lib/runtime/orchestrator.js +158 -3
- package/lib/v2/conformance.js +13 -3
- package/package.json +1 -1
- package/templates/project/AGENTS.md +5 -4
- package/templates/shared/skills/scrumrun/SKILL.md +28 -26
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes follow Semantic Versioning.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 3.0.2 - 2026-08-31
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Planning artifact amendments.** `scrumrun plan task|feature|sprint --amend <ID>` updates planning truth through the CLI rather than hand-editing Markdown. It supports title and structured fields plus generic repeated `--section "Heading=content"`, so new scope context does not require another command. Task Feature/Sprint relations update their projections atomically.
|
|
12
|
+
|
|
13
|
+
### Safety
|
|
14
|
+
|
|
15
|
+
- A Task can be amended only while `backlog` or `proposed`; once started, its approved scope is preserved and new work belongs in a follow-up Task. Runs, Reviews, confirmed memory, and Guardrails remain append-only/evidence-led by design.
|
|
16
|
+
|
|
17
|
+
## 3.0.1 - 2026-08-31
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Orphan Task recovery.** `doctor --strict` now reports `TASK_ORPHANED` when an active Task has no canonical Run. `scrumrun repair --recover-orphan-tasks` previews the affected Tasks; only `scrumrun repair --recover-orphan-tasks --apply` resets them to `backlog`, preserves a byte-exact backup, and never fabricates a Run or execution history.
|
|
22
|
+
- **Direct CLI grammar.** `scrumrun plan task --start TASK-NNN` is now the canonical command form. `scrumrun sc ...` and `/sc` remain compatibility shortcuts, but generated instructions, approval output, recovery guidance, and documentation use the direct installed CLI, avoiding accidental `npx` execution loops.
|
|
23
|
+
|
|
7
24
|
## 3.0.0 - 2026-08-31
|
|
8
25
|
|
|
9
26
|
### Changed
|
package/CORE.md
CHANGED
|
@@ -9,7 +9,7 @@ Method version: `2.0.0`
|
|
|
9
9
|
The canonical command is:
|
|
10
10
|
|
|
11
11
|
```text
|
|
12
|
-
|
|
12
|
+
scrumrun <noun> <subject> <action> [args]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
The five nouns are:
|
|
@@ -22,7 +22,7 @@ The five nouns are:
|
|
|
22
22
|
|
|
23
23
|
Incomplete syntax lists only valid next tokens. Unknown syntax never guesses or mutates.
|
|
24
24
|
|
|
25
|
-
The command manifest at `lib/commands/manifest.js` generates client prompts, compatibility adapters, help, and grammar tests.
|
|
25
|
+
The command manifest at `lib/commands/manifest.js` generates client prompts, compatibility adapters, help, and grammar tests. The installed CLI is canonical; `/sc` is a client shortcut. A v1 upgrade may install generated compatibility adapters for one release cycle.
|
|
26
26
|
|
|
27
27
|
## Entity model
|
|
28
28
|
|
|
@@ -84,7 +84,9 @@ AGENTS.md
|
|
|
84
84
|
|
|
85
85
|
**Before querying project state, read `.scrumrun/method.json`.** Its `paths` block is the authoritative index of every canonical location in this project. Navigate by that index; if a path is not declared there, it is not canonical truth. Directory listing and grep are fallbacks — never the first step. A ScrumRun-aware agent must never search for `goals/`, `backlog.md`, `sprint.md`, or any legacy layout: those are absent by design once migration completes and are surfaced only through `.scrumrun/.migration-backup/`.
|
|
86
86
|
|
|
87
|
-
**Never write Run events by hand.** After approval, work directly in code and in the linked Task Markdown. Finish the normal session once with `scrumrun
|
|
87
|
+
**Never write Run events by hand.** After approval, work directly in code and in the linked Task Markdown. Finish the normal session once with `scrumrun plan run --finalize RUN-NNN`; the CLI then audits the complete workspace delta, verifies Guardrails and evidence, and writes the validated Run event chain. Do not use `npx scrumrun@latest` during execution. The older `--validate | --learn | --complete | --satisfy-guardrail | --authorize-mutation | --record-mutation` operations remain available only for an owner-requested strict path. Existing hand-written Runs can be recovered with `scrumrun plan run --normalize-legacy` (byte-exact original preserved in `.scrumrun/.migration-backup/runs/`).
|
|
88
|
+
|
|
89
|
+
**Amend planning truth through the CLI, never by hand.** Before execution, use `scrumrun plan task|feature|sprint --amend <ID>` to adjust the title, structured fields, or any named body section (`--section "Heading=content"`). A Task may be amended only in `backlog` or `proposed`; changing its `--feature` or `--sprint` also synchronizes the related projections atomically. Runs, Reviews, confirmed memory, and Guardrails are evidence/history and are not amendable: append a transition, record a new Review, or supersede/deprecate the old fact instead.
|
|
88
90
|
|
|
89
91
|
Canonical truth is Markdown. SQLite/cache data stores only rebuildable indexes, symbol projections, relations, and bounded context packages. Deleting `.cache/` must never delete authored truth.
|
|
90
92
|
|
|
@@ -112,7 +114,7 @@ Normal read path:
|
|
|
112
114
|
4. only the canonical ids and evidence relevant to current work;
|
|
113
115
|
5. `.scrumrun/core.md` when method details or exceptional transitions are needed.
|
|
114
116
|
|
|
115
|
-
The briefing is a progressive-disclosure index, not full context. Read it first and follow its pointers to specific artifacts (`## Where to look`, `
|
|
117
|
+
The briefing is a progressive-disclosure index, not full context. Read it first and follow its pointers to specific artifacts (`## Where to look`, `scrumrun knowledge study "<topic>"`). Go deeper — a Task body, a Run ledger, a Decision — only when the briefing lacks what you need. Never treat the briefing as a substitute for the canonical artifact it points to.
|
|
116
118
|
|
|
117
119
|
Lean mode is this bounded read policy; it is not permission to omit canonical truth.
|
|
118
120
|
|
|
@@ -156,7 +158,7 @@ Intake must:
|
|
|
156
158
|
|
|
157
159
|
Policy evaluation is structured per active `GR-NNN`: `passed`, `blocked`, or `deferred`. A block must cite the exact Guardrail id and reason code. Deferred checks must be visible in the plan and re-evaluated at their named execution boundary; they are never silently counted as passed. Invalid/duplicate Guardrails or configuration that weakens approval block conformance and intake.
|
|
158
160
|
|
|
159
|
-
The agent may assert the classification explicitly with `
|
|
161
|
+
The agent may assert the classification explicitly with `scrumrun plan intake "…" --type fix|task|feature|docs|discovery`, overriding keyword inference (validated, with a stable reason). It may also attach a short technical explanation with `--preview "…"`, rendered in the pretty terminal layout, bound into the approval token, and stored as `## Preview` on the Task.
|
|
160
162
|
|
|
161
163
|
Before approval, do not create canonical files, update status, edit application code, or retain request content outside ignored disposable context cache. The approval token binds both canonical context and the workspace fingerprint; drift in either requires a new intake. Ambiguous acknowledgement is not approval.
|
|
162
164
|
|
|
@@ -187,7 +189,7 @@ Rules:
|
|
|
187
189
|
- before changing application/source files, issue a short-lived path-scoped mutation permit and record the verified before/after hashes in the Run;
|
|
188
190
|
- unrecorded workspace drift, policy drift, out-of-scope paths, unsafe symlinks, new secret-like content, or unresolved obligations block validation/completion;
|
|
189
191
|
- learning proposes memory candidates after validation and never auto-confirms AI inference;
|
|
190
|
-
- record a `## Technical Summary` at completion with `
|
|
192
|
+
- record a `## Technical Summary` at completion with `scrumrun plan run --complete --summary "…"` so the next agent inherits what was actually done;
|
|
191
193
|
- complete a Sprint only when all its included Tasks meet the Sprint exit gate;
|
|
192
194
|
- do not mark work complete merely because time or token budget ended.
|
|
193
195
|
|
|
@@ -197,7 +199,7 @@ Task/Run pair mutations use an ignored durable journal under `.scrumrun/.backup/
|
|
|
197
199
|
|
|
198
200
|
### Backlog and sequencing
|
|
199
201
|
|
|
200
|
-
Backlog is the queue of Tasks with `status: backlog`, ordered oldest-first by id. When a Run completes, the briefing's `## Next Up` names the next backlog Task. `
|
|
202
|
+
Backlog is the queue of Tasks with `status: backlog`, ordered oldest-first by id. When a Run completes, the briefing's `## Next Up` names the next backlog Task. `scrumrun plan task --next` shows it; `scrumrun plan task --start [TASK-NNN]` promotes it to `running`, creates its first Run, re-evaluates policy, and records the agent identity. Starting is itself the explicit approval (I-01): no work executes silently, and the owner can always say "not now".
|
|
201
203
|
|
|
202
204
|
### Agent identity and assignment
|
|
203
205
|
|
|
@@ -264,7 +266,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
264
266
|
|
|
265
267
|
## Command reference
|
|
266
268
|
|
|
267
|
-
###
|
|
269
|
+
### `scrumrun plan`
|
|
268
270
|
|
|
269
271
|
- `task --add|--list|--show|--run|--audit|--cancel|--retry|--next|--start [TASK-NNN]`
|
|
270
272
|
- `sprint --add|--list|--show|--start|--complete|--block`
|
|
@@ -273,7 +275,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
273
275
|
- `intake <request> [--type fix|task|feature|docs|discovery] [--preview "…"]`
|
|
274
276
|
- `challenge <question>`
|
|
275
277
|
|
|
276
|
-
###
|
|
278
|
+
### `scrumrun knowledge`
|
|
277
279
|
|
|
278
280
|
- `fact --add|--list|--show|--approve|--reject|--deprecate|--invalidate`
|
|
279
281
|
- `decision --add|--list|--show|--resolve|--deprecate|--invalidate`
|
|
@@ -284,12 +286,12 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
284
286
|
- `study <focus>`
|
|
285
287
|
- `vault --add|--list|--show|--remove|--path`
|
|
286
288
|
|
|
287
|
-
###
|
|
289
|
+
### `scrumrun rules`
|
|
288
290
|
|
|
289
291
|
- `guardrail --add|--list|--show|--retire`
|
|
290
292
|
- `reviewer --add|--list|--show|--run`
|
|
291
293
|
|
|
292
|
-
###
|
|
294
|
+
### `scrumrun review`
|
|
293
295
|
|
|
294
296
|
- `code --run`
|
|
295
297
|
- `artifact --run`
|
|
@@ -298,7 +300,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
298
300
|
|
|
299
301
|
Review is read-only unless fixes are separately authorized. Report findings by severity with evidence.
|
|
300
302
|
|
|
301
|
-
###
|
|
303
|
+
### `scrumrun config`
|
|
302
304
|
|
|
303
305
|
- `project --show|--language|--interaction|--approval|--quick-tasks`
|
|
304
306
|
- `init --local|--shared|--force`
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
ScrumRun gives an agent a small command surface and a precise project memory: what should be done, how each attempt happened, which decisions constrain the code, and why the architecture exists in its current form.
|
|
6
6
|
|
|
7
|
-
**Package:** `3.0.
|
|
7
|
+
**Package:** `3.0.2` · **Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
|
|
8
8
|
|
|
9
9
|
**New here?** Read the [Quickstart](docs/QUICKSTART.md) — first Run in under 10 minutes, no `SPEC.md` reading required. Full docs map in [`docs/INDEX.md`](docs/INDEX.md).
|
|
10
10
|
|
|
@@ -52,13 +52,13 @@ Use the installed `scrumrun` command for project work. `npx` is appropriate for
|
|
|
52
52
|
|
|
53
53
|
`install` adds the client integration; `init` creates the project tree. Initialization is local by default: `.scrumrun/` and the generated agent hint are added to `.git/info/exclude`. Use `--shared` when the team wants to commit the project memory.
|
|
54
54
|
|
|
55
|
-
ScrumRun
|
|
55
|
+
ScrumRun's canonical CLI is:
|
|
56
56
|
|
|
57
57
|
```text
|
|
58
|
-
|
|
58
|
+
scrumrun <noun> <subject> <action> [args]
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
The five nouns are `plan`, `knowledge`, `rules`, `review`, and `config`.
|
|
61
|
+
The five nouns are `plan`, `knowledge`, `rules`, `review`, and `config`. `/sc` is an optional AI-client shortcut; `scrumrun sc ...` remains a compatibility alias for existing integrations.
|
|
62
62
|
|
|
63
63
|
## Daily flow
|
|
64
64
|
|
|
@@ -88,11 +88,23 @@ EXECUTING → VALIDATING → LEARNING → COMPLETED | FAILED | BLOCKED
|
|
|
88
88
|
Every approved Task carries an `## Acceptance Criteria` section so "done" is defined before work begins. After approval, the agent works directly in code and the Task Markdown. It adds `## Technical Summary` and, when a non-automatic rule needs proof, a compact `## Guardrail Evidence` section. One final checkpoint closes the work:
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
|
-
scrumrun
|
|
91
|
+
scrumrun plan run --finalize RUN-001
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
The checkpoint validates the complete delta, policy, protected paths, secret boundary, acceptance evidence, and every Guardrail before writing the Run ledger and synchronizing the Task. Failed retries remain available as separate Runs.
|
|
95
95
|
|
|
96
|
+
Before a Task starts, refine it through the CLI rather than hand-editing Markdown. `--amend` updates title, request, acceptance criteria, Feature/Sprint links, task type, or any named section while preserving its ID and status. It synchronizes related Feature/Sprint projections atomically.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
scrumrun plan task --amend TASK-153 \
|
|
100
|
+
--title "Organization Aside and context selector" \
|
|
101
|
+
--request "Add shared organization navigation, context selection, routes, and authorization boundaries." \
|
|
102
|
+
--acceptance "Organization context is available before protected routes render." \
|
|
103
|
+
--section "Architecture Notes=Navigation stays in the Aside; authorization stays server-side."
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Tasks become immutable in scope once started; create a follow-up Task for a new request. Runs, Reviews, confirmed memory, and Guardrails are deliberately append-only/evidence-led rather than editable. See [the command reference](docs/COMMANDS.md#what-can-be-changed) for the complete artifact matrix.
|
|
107
|
+
|
|
96
108
|
Each Run contains a machine-validated event ledger. Events have stable ids such as `RUN-044-EVT-003`, RFC3339 timestamps, actors, reasons, and typed evidence for commands, tests, files, reviews, decisions, insights, and risks. Run is the only operational history; Task keeps its approved scope and synchronized current status without duplicating those events. Completion is rejected when validation or learning evidence is missing.
|
|
97
109
|
|
|
98
110
|
Linked Task/Run writes use a durable ignored transaction journal. Captured failures roll back immediately; interrupted operations are recovered byte-exactly on retry or through explicit `doctor --recover`. Read-only audit reports pending recovery and never repairs state silently.
|
|
@@ -154,21 +166,21 @@ It is progressive disclosure: the briefing is enough for most work; the agent fo
|
|
|
154
166
|
Update the client integrations and automatically run a read-only migration preflight:
|
|
155
167
|
|
|
156
168
|
```bash
|
|
157
|
-
|
|
169
|
+
scrumrun update
|
|
158
170
|
```
|
|
159
171
|
|
|
160
172
|
This shows the source inventory, proposed mappings, and blockers without changing project data. Apply only the verified plan with:
|
|
161
173
|
|
|
162
174
|
```bash
|
|
163
|
-
|
|
175
|
+
scrumrun update --migrate
|
|
164
176
|
```
|
|
165
177
|
|
|
166
178
|
The standalone workflow remains available:
|
|
167
179
|
|
|
168
180
|
```bash
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
scrumrun migrate --to 2 --dry-run
|
|
182
|
+
scrumrun migrate --to 2 --apply
|
|
183
|
+
scrumrun migrate --to 2 --rollback
|
|
172
184
|
```
|
|
173
185
|
|
|
174
186
|
Migration uses content hashes, a byte-exact ignored backup, staging validation, an atomic directory switch, a source-to-destination report, idempotent replay, and rollback protection. It also recognizes incomplete hybrid v1/v2 trees, reuses already-linked canonical work, and normalizes only deterministic schema aliases. Early v2 Run prose is preflighted and upgraded to the structured ledger by the same explicit `update --migrate` gate; ambiguous paths become evidenced snapshots instead of invented transitions. Legacy-only files leave the active tree but remain byte-exact in the ignored backup; vault contents remain local. Ambiguous history remains an explicit warning, and the migrator never invents a Sprint or Run.
|
|
@@ -176,16 +188,26 @@ Migration uses content hashes, a byte-exact ignored backup, staging validation,
|
|
|
176
188
|
For projects that already have v2 directories but contain pre-v2 Markdown records without YAML frontmatter, use the explicit repair gate:
|
|
177
189
|
|
|
178
190
|
```bash
|
|
179
|
-
|
|
180
|
-
|
|
191
|
+
scrumrun repair
|
|
192
|
+
scrumrun repair --apply
|
|
181
193
|
```
|
|
182
194
|
|
|
183
195
|
Repair converts deterministic `## Metadata` fields into v2 frontmatter, preserves the authored body, recovers IDs from canonical filenames, and stores byte-exact backups under `.scrumrun/.migration-backup/repair/`. It does not guess ambiguous relationships; validate afterward with `doctor --strict`.
|
|
184
196
|
|
|
197
|
+
If `doctor --strict` reports `TASK_ORPHANED`, first inspect the exact recovery plan, then explicitly reset only those active Tasks to backlog and start the intended one normally:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
scrumrun repair --recover-orphan-tasks
|
|
201
|
+
scrumrun repair --recover-orphan-tasks --apply
|
|
202
|
+
scrumrun plan task --start TASK-144
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Recovery never invents a Run or historical events; it creates a byte-exact backup before changing the Task. The final `--start` is the intentional action that creates its first Run.
|
|
206
|
+
|
|
185
207
|
After migration or an integration update, verify both installed assets and project state:
|
|
186
208
|
|
|
187
209
|
```bash
|
|
188
|
-
|
|
210
|
+
scrumrun doctor codex --strict
|
|
189
211
|
```
|
|
190
212
|
|
|
191
213
|
`doctor` compares managed prompt/skill contents with the package, so an obsolete installation is reported as `stale` rather than `ok` merely because the file exists.
|
|
@@ -252,42 +274,42 @@ Rules:
|
|
|
252
274
|
scrumrun commands
|
|
253
275
|
|
|
254
276
|
# plan without writes, then approve the emitted token
|
|
255
|
-
scrumrun
|
|
256
|
-
scrumrun
|
|
277
|
+
scrumrun plan intake "Fix pricing rounding" --type fix --preview "Rounding moved after tax calc"
|
|
278
|
+
scrumrun plan intake --approve <token>
|
|
257
279
|
|
|
258
280
|
# record what was done at completion, so the next agent inherits it
|
|
259
|
-
scrumrun
|
|
281
|
+
scrumrun plan run --finalize RUN-001 --summary "Moved rounding after tax calc in checkout/pricing.ts"
|
|
260
282
|
|
|
261
283
|
# auto-sequencing: surface and start the next backlog Task
|
|
262
|
-
scrumrun
|
|
263
|
-
scrumrun
|
|
284
|
+
scrumrun plan task --next
|
|
285
|
+
scrumrun plan task --start TASK-009
|
|
264
286
|
|
|
265
287
|
# authorize and record a material source mutation
|
|
266
|
-
scrumrun
|
|
267
|
-
scrumrun
|
|
288
|
+
scrumrun plan run --authorize-mutation RUN-001 --path src/pricing.ts # strict mode only
|
|
289
|
+
scrumrun plan run --record-mutation RUN-001 --permit MUT-... --note "Pricing change recorded"
|
|
268
290
|
|
|
269
291
|
# record an audit-derived Review, then resolve a persisted completion gate
|
|
270
|
-
scrumrun
|
|
271
|
-
scrumrun
|
|
292
|
+
scrumrun review artifact --run
|
|
293
|
+
scrumrun review artifact --record --task TASK-001 --run RUN-001 --evidence "npm test: passed"
|
|
272
294
|
|
|
273
295
|
# memory lifecycle
|
|
274
|
-
scrumrun
|
|
275
|
-
scrumrun
|
|
276
|
-
scrumrun
|
|
296
|
+
scrumrun knowledge insight --propose "Pricing stays in backend" --evidence src/pricing.ts
|
|
297
|
+
scrumrun knowledge insight --confirm INS-001
|
|
298
|
+
scrumrun knowledge study calculateFinalPrice
|
|
277
299
|
|
|
278
300
|
# rebuild or inspect the derived graph
|
|
279
|
-
scrumrun
|
|
280
|
-
scrumrun
|
|
301
|
+
scrumrun knowledge map --build
|
|
302
|
+
scrumrun knowledge map --show
|
|
281
303
|
|
|
282
304
|
# read a Run as a human timeline instead of raw ledger JSON
|
|
283
|
-
scrumrun
|
|
305
|
+
scrumrun plan run --render RUN-001
|
|
284
306
|
|
|
285
307
|
# aggregate every Run in the project (p50/p95 durations, retries, guardrail counts)
|
|
286
|
-
scrumrun
|
|
287
|
-
scrumrun
|
|
308
|
+
scrumrun plan run --stats
|
|
309
|
+
scrumrun plan run --stats --task TASK-001 --json
|
|
288
310
|
|
|
289
311
|
# preview a canonical-transaction recovery before touching disk
|
|
290
|
-
|
|
312
|
+
scrumrun config doctor --recover --dry-run
|
|
291
313
|
```
|
|
292
314
|
|
|
293
315
|
The command manifest in `lib/commands/manifest.js` generates help and compatibility adapters, preventing client grammar drift. A recorded artifact Review cannot self-declare success: ScrumRun reruns the audit and derives the `REV-NNN` verdict from the result.
|
package/SPEC.md
CHANGED
|
@@ -274,7 +274,7 @@ scrumrun migrate --to 2 --apply
|
|
|
274
274
|
scrumrun migrate --to 2 --rollback
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
`
|
|
277
|
+
`scrumrun update` performs the same read-only preflight when run inside a v1 project and leaves project data untouched. `update --migrate` is an explicit request to apply the verified plan; it is not implicit migration.
|
|
278
278
|
|
|
279
279
|
Inside an early v2 project, the same commands preflight and explicitly upgrade legacy Run prose to ledger schema 1. Deterministic transition chains are recovered; incomplete history becomes an evidenced snapshot. Apply keeps byte-exact ignored backups, verifies hashes, is idempotent, and supports rollback that refuses to erase later Run changes.
|
|
280
280
|
|
|
@@ -318,17 +318,17 @@ Legacy sprint entries become Tasks. History entries become Runs only with an evi
|
|
|
318
318
|
- **I-21** Material mutations are policy-bound, path-scoped, hash-verified, append-only, and fail closed on bypass; unresolved Guardrail obligations block completion.
|
|
319
319
|
- **I-22** The semantic index's declared search backend must match the runtime capabilities of the current Node.js SQLite build; conformance flags a mismatch instead of relying on lazy runtime fallback.
|
|
320
320
|
- **I-23** `method.json` declares the canonical path index for every artifact family so agents navigate by declaration, not by search. Missing or drifted paths fail conformance; grep and directory scans are fallbacks, never the first step.
|
|
321
|
-
- **I-24** Runs are only mutated through the CLI. A canonical Run whose ledger fails validation is a bypass — conformance reports `RUN_WRITE_BYPASS` with a pointer to the recovery command `
|
|
321
|
+
- **I-24** Runs are only mutated through the CLI. A canonical Run whose ledger fails validation is a bypass — conformance reports `RUN_WRITE_BYPASS` with a pointer to the recovery command `scrumrun plan run --normalize-legacy`, which collapses the bad ledger into a single `snapshot` event and preserves the byte-exact original under `.scrumrun/.migration-backup/runs/`.
|
|
322
322
|
|
|
323
323
|
## 11. Command grammar
|
|
324
324
|
|
|
325
325
|
The only canonical root is:
|
|
326
326
|
|
|
327
327
|
```text
|
|
328
|
-
|
|
328
|
+
scrumrun <noun> <subject> <action> [args]
|
|
329
329
|
```
|
|
330
330
|
|
|
331
|
-
Exactly five nouns exist: `plan`, `knowledge`, `rules`, `review`, and `config`. The implementation manifest is the command source of truth for help and client adapters.
|
|
331
|
+
Exactly five nouns exist: `plan`, `knowledge`, `rules`, `review`, and `config`. The implementation manifest is the command source of truth for help and client adapters. The installed direct CLI is canonical; `/sc` and generated v1 aliases may remain as compatibility shortcuts for one release cycle and must execute the canonical route.
|
|
332
332
|
|
|
333
333
|
Unknown syntax fails deterministically and never guesses a mutation.
|
|
334
334
|
|
package/bin/scrumrun.js
CHANGED
|
@@ -31,7 +31,7 @@ const { ARTIFACT_TYPES, ArtifactRepository } = require(path.join(root, "lib", "v
|
|
|
31
31
|
const { aliases: COMMAND_ALIASES, resolveAlias, resolveRoute } = require(path.join(root, "lib", "commands", "manifest"));
|
|
32
32
|
const { renderCommandHelp, renderCompatibilityPrompt, renderRootPrompt } = require(path.join(root, "lib", "commands", "render"));
|
|
33
33
|
const { planRequest } = require(path.join(root, "lib", "runtime", "request-engine"));
|
|
34
|
-
const { addPlanArtifact, approveRequest, finalizeRun, nextBacklogTask, refreshErrors, refreshState, retryTask, startBacklogTask, transitionRun } = require(path.join(root, "lib", "runtime", "orchestrator"));
|
|
34
|
+
const { addPlanArtifact, amendPlanArtifact, approveRequest, finalizeRun, nextBacklogTask, refreshErrors, refreshState, retryTask, startBacklogTask, transitionRun } = require(path.join(root, "lib", "runtime", "orchestrator"));
|
|
35
35
|
const { authorizeMutation, recordMutation, satisfyGuardrail } = require(path.join(root, "lib", "runtime", "mutation-gateway"));
|
|
36
36
|
const { recordArtifactReview } = require(path.join(root, "lib", "runtime", "review-service"));
|
|
37
37
|
const { createMemory, listMemory, showMemory, transitionMemory } = require(path.join(root, "lib", "memory", "service"));
|
|
@@ -55,8 +55,8 @@ function usage() {
|
|
|
55
55
|
|
|
56
56
|
Usage:
|
|
57
57
|
scrumrun --version
|
|
58
|
-
scrumrun
|
|
59
|
-
scrumrun sc <noun> <subject> <action> [args]
|
|
58
|
+
scrumrun <noun> <subject> <action> [args]
|
|
59
|
+
scrumrun sc <noun> <subject> <action> [args] # compatibility alias
|
|
60
60
|
scrumrun install [all|codex|opencode|claude] [--force]
|
|
61
61
|
scrumrun update [all|codex|opencode|claude] [--no-migrate] [--verbose]
|
|
62
62
|
scrumrun init [--local|--shared] [--lean] [--no-agent-hint] [--force]
|
|
@@ -67,18 +67,18 @@ Usage:
|
|
|
67
67
|
scrumrun migrate --to 2 --apply
|
|
68
68
|
scrumrun migrate --to 2 --rollback
|
|
69
69
|
scrumrun doctor [all|codex|opencode|claude] [--strict] [--recover]
|
|
70
|
-
scrumrun repair [--apply]
|
|
70
|
+
scrumrun repair [--recover-orphan-tasks] [--apply]
|
|
71
71
|
scrumrun uninstall [--force]
|
|
72
72
|
|
|
73
73
|
Install:
|
|
74
74
|
npm i -g scrumrun@latest # recommended
|
|
75
|
-
npx scrumrun@latest <command> #
|
|
75
|
+
npx scrumrun@latest <command> # one-off recovery only; never use in an agent loop
|
|
76
76
|
|
|
77
77
|
Examples:
|
|
78
78
|
scrumrun install
|
|
79
79
|
scrumrun init
|
|
80
80
|
scrumrun status
|
|
81
|
-
scrumrun
|
|
81
|
+
scrumrun knowledge decision --list
|
|
82
82
|
scrumrun migrate --to 2 --dry-run
|
|
83
83
|
`);
|
|
84
84
|
}
|
|
@@ -318,14 +318,14 @@ function migrationPreflightOnUpdate({ apply = false } = {}) {
|
|
|
318
318
|
return { status: "blocked" };
|
|
319
319
|
}
|
|
320
320
|
if (!apply) {
|
|
321
|
-
console.log("\nThe project remains unchanged. Re-run update to apply the verified plan, or keep opt-out with:
|
|
321
|
+
console.log("\nThe project remains unchanged. Re-run update to apply the verified plan, or keep opt-out with: scrumrun update --no-migrate");
|
|
322
322
|
return { status: "ready" };
|
|
323
323
|
}
|
|
324
324
|
const result = applyRunLedgerMigration(process.cwd());
|
|
325
325
|
refreshState(path.join(process.cwd(), ".scrumrun"));
|
|
326
326
|
console.log("\nApplied the verified ScrumRun Run ledger schema migration.");
|
|
327
327
|
console.log(`Source fingerprint: ${result.plan.fingerprint}`);
|
|
328
|
-
console.log("Rollback remains available with:
|
|
328
|
+
console.log("Rollback remains available with: scrumrun migrate --to 2 --rollback");
|
|
329
329
|
return { status: result.status, result };
|
|
330
330
|
}
|
|
331
331
|
} catch {
|
|
@@ -344,13 +344,13 @@ function migrationPreflightOnUpdate({ apply = false } = {}) {
|
|
|
344
344
|
return { status: "blocked" };
|
|
345
345
|
}
|
|
346
346
|
if (!apply) {
|
|
347
|
-
console.log("\nThe project remains unchanged. Re-run update to apply the verified plan, or keep opt-out with:
|
|
347
|
+
console.log("\nThe project remains unchanged. Re-run update to apply the verified plan, or keep opt-out with: scrumrun update --no-migrate");
|
|
348
348
|
return { status: "ready" };
|
|
349
349
|
}
|
|
350
350
|
const result = applyMigration(process.cwd(), { plan: preview.plan });
|
|
351
351
|
console.log("\nApplied the verified ScrumRun v1 → v2 project migration.");
|
|
352
352
|
console.log(`Source fingerprint: ${result.manifest.sourceInventory.rootSha256}`);
|
|
353
|
-
console.log("Rollback remains available with:
|
|
353
|
+
console.log("Rollback remains available with: scrumrun migrate --to 2 --rollback");
|
|
354
354
|
return { status: "applied", result };
|
|
355
355
|
} catch (error) {
|
|
356
356
|
console.error(`Project migration preflight failed: ${error.message}`);
|
|
@@ -1157,7 +1157,7 @@ function commandList() {
|
|
|
1157
1157
|
CLI helpers:
|
|
1158
1158
|
scrumrun status
|
|
1159
1159
|
scrumrun commands
|
|
1160
|
-
scrumrun
|
|
1160
|
+
scrumrun knowledge decision --list
|
|
1161
1161
|
scrumrun vault add "NAME" "local-dev-value"
|
|
1162
1162
|
scrumrun context show
|
|
1163
1163
|
scrumrun backlog add "Sprint 01"
|
|
@@ -1392,7 +1392,7 @@ function runSemanticContext(subject, args) {
|
|
|
1392
1392
|
}
|
|
1393
1393
|
const mapFile = path.join(process.cwd(), ".scrumrun", "map.md");
|
|
1394
1394
|
const status = mapStatus(process.cwd());
|
|
1395
|
-
if (status.stale) throw new Error(`Generated map.md is stale (${status.reason || status.error || "unknown reason"}); run
|
|
1395
|
+
if (status.stale) throw new Error(`Generated map.md is stale (${status.reason || status.error || "unknown reason"}); run scrumrun knowledge map --build.`);
|
|
1396
1396
|
console.log(fs.readFileSync(mapFile, "utf8"));
|
|
1397
1397
|
return;
|
|
1398
1398
|
}
|
|
@@ -1456,7 +1456,7 @@ function executeRootRoute(route) {
|
|
|
1456
1456
|
return;
|
|
1457
1457
|
}
|
|
1458
1458
|
console.log(`Next backlog Task: ${next.id} — ${next.title || next.id}`);
|
|
1459
|
-
console.log(`Start it with: scrumrun
|
|
1459
|
+
console.log(`Start it with: scrumrun plan task --start ${next.id}`);
|
|
1460
1460
|
return;
|
|
1461
1461
|
}
|
|
1462
1462
|
if (noun === "plan" && subject === "task" && routeArgs[0] === "--start") {
|
|
@@ -1475,6 +1475,27 @@ function executeRootRoute(route) {
|
|
|
1475
1475
|
console.log(`Started ${result.task.id} (${result.run.id}) assigned to ${result.task.assignee || "agent"}.`);
|
|
1476
1476
|
return;
|
|
1477
1477
|
}
|
|
1478
|
+
if (noun === "plan" && ["task", "feature", "sprint"].includes(subject) && routeArgs[0] === "--amend") {
|
|
1479
|
+
const id = routeArgs[1];
|
|
1480
|
+
if (!id) throw new Error(`--amend requires a ${subject.toUpperCase()}-NNN id.`);
|
|
1481
|
+
const amendArgs = routeArgs.slice(2);
|
|
1482
|
+
const amendValue = (flag) => amendArgs.includes(flag) ? optionValue(amendArgs, flag) : undefined;
|
|
1483
|
+
const result = amendPlanArtifact(process.cwd(), subject, id, {
|
|
1484
|
+
title: amendValue("--title"),
|
|
1485
|
+
request: amendValue("--request"),
|
|
1486
|
+
acceptance: amendArgs.includes("--acceptance") ? optionValues(amendArgs, "--acceptance") : undefined,
|
|
1487
|
+
purpose: amendValue("--purpose"),
|
|
1488
|
+
exitCriteria: amendArgs.includes("--exit-criteria") ? optionValues(amendArgs, "--exit-criteria") : undefined,
|
|
1489
|
+
timebox: amendValue("--timebox"),
|
|
1490
|
+
exitGate: amendArgs.includes("--exit-gate") ? optionValues(amendArgs, "--exit-gate") : undefined,
|
|
1491
|
+
sections: optionValues(amendArgs, "--section"),
|
|
1492
|
+
type: amendValue("--type"),
|
|
1493
|
+
feature: amendValue("--feature"),
|
|
1494
|
+
sprint: amendValue("--sprint")
|
|
1495
|
+
});
|
|
1496
|
+
console.log(`Amended ${result.record.id}: ${path.relative(process.cwd(), result.file)} (status remains ${result.record.status}).`);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1478
1499
|
if (noun === "plan" && ["task", "feature", "sprint"].includes(subject) && routeArgs[0] === "--add") {
|
|
1479
1500
|
const label = removeOptionPairs(routeArgs.slice(1), ["--type", "--status"])
|
|
1480
1501
|
.filter((arg) => !arg.startsWith("--"))
|
|
@@ -1689,7 +1710,7 @@ function runRoot(parts) {
|
|
|
1689
1710
|
|
|
1690
1711
|
function runCompatibilityAlias(alias, parts) {
|
|
1691
1712
|
const route = resolveAlias(alias, parts);
|
|
1692
|
-
console.warn(`Deprecated: ${alias} now executes
|
|
1713
|
+
console.warn(`Deprecated: ${alias} now executes scrumrun ${route.noun} ${route.subject}.`);
|
|
1693
1714
|
if (route.note) console.warn(route.note);
|
|
1694
1715
|
if (alias === "sc-backlog") return runBacklog(parts);
|
|
1695
1716
|
if (alias !== "sc-init") chdirToProjectRoot();
|
|
@@ -1705,7 +1726,7 @@ function printCore({ pathOnly = false, promptOnly = false } = {}) {
|
|
|
1705
1726
|
if (promptOnly) {
|
|
1706
1727
|
console.log(`Read AGENTS.md, .scrumrun/guardrails.md, and .scrumrun/state.md first.
|
|
1707
1728
|
Follow ScrumRun 2.0 and load only the canonical ids/evidence relevant to the request.
|
|
1708
|
-
|
|
1729
|
+
Use the installed CLI as scrumrun <noun> <subject> <action>; /sc is only a client shortcut.
|
|
1709
1730
|
Keep intake read-only; do not create a Task or Run until explicit approval.`);
|
|
1710
1731
|
return;
|
|
1711
1732
|
}
|
|
@@ -2180,7 +2201,7 @@ function statusProject() {
|
|
|
2180
2201
|
}
|
|
2181
2202
|
console.log("");
|
|
2182
2203
|
console.log(`Migration record: ${fs.existsSync(path.join(scrumDir, ".migration", "v1-to-v2", "manifest.json")) ? "v1-to-v2 applied" : "not applicable / native v2"}`);
|
|
2183
|
-
console.log(`Canonical command:
|
|
2204
|
+
console.log(`Canonical command: scrumrun <noun> <subject> <action>`);
|
|
2184
2205
|
return;
|
|
2185
2206
|
}
|
|
2186
2207
|
const required = [
|
|
@@ -2236,24 +2257,24 @@ function promptCommand(parts) {
|
|
|
2236
2257
|
const kind = parts[0];
|
|
2237
2258
|
const text = joinText(parts.slice(1));
|
|
2238
2259
|
const prompts = {
|
|
2239
|
-
intake:
|
|
2240
|
-
study:
|
|
2241
|
-
challenge:
|
|
2242
|
-
know:
|
|
2243
|
-
"context-build":
|
|
2244
|
-
"context-update":
|
|
2245
|
-
"context-show":
|
|
2246
|
-
context:
|
|
2247
|
-
vault:
|
|
2248
|
-
"goal-set":
|
|
2249
|
-
"goal-new":
|
|
2250
|
-
goal:
|
|
2251
|
-
"sprint-add":
|
|
2252
|
-
"sprint-new":
|
|
2253
|
-
"sprint-run":
|
|
2254
|
-
"backlog-add":
|
|
2255
|
-
backlog:
|
|
2256
|
-
status:
|
|
2260
|
+
intake: `scrumrun plan intake ${text}`.trim(),
|
|
2261
|
+
study: `scrumrun knowledge study${text ? ` ${text}` : ""}`,
|
|
2262
|
+
challenge: `scrumrun plan challenge ${text}`.trim(),
|
|
2263
|
+
know: `scrumrun knowledge fact --add ${text}`.trim(),
|
|
2264
|
+
"context-build": `scrumrun knowledge context --build${text ? ` ${text}` : ""}`,
|
|
2265
|
+
"context-update": `scrumrun knowledge context --update${text ? ` ${text}` : ""}`,
|
|
2266
|
+
"context-show": `scrumrun knowledge context --show${text ? ` ${text}` : ""}`,
|
|
2267
|
+
context: `scrumrun knowledge context ${text}`.trim(),
|
|
2268
|
+
vault: `scrumrun knowledge vault ${text}`.trim(),
|
|
2269
|
+
"goal-set": `scrumrun plan feature --add ${text}`.trim(),
|
|
2270
|
+
"goal-new": `scrumrun plan feature --add ${text}`.trim(),
|
|
2271
|
+
goal: `scrumrun plan feature --add ${text}`.trim(),
|
|
2272
|
+
"sprint-add": `scrumrun plan sprint --add ${text}`.trim(),
|
|
2273
|
+
"sprint-new": `scrumrun plan sprint --add ${text}`.trim(),
|
|
2274
|
+
"sprint-run": `scrumrun plan task --run ${text}`.trim(),
|
|
2275
|
+
"backlog-add": `scrumrun plan task --add ${text} --status backlog`.trim(),
|
|
2276
|
+
backlog: `scrumrun plan task --add ${text} --status backlog`.trim(),
|
|
2277
|
+
status: `scrumrun plan sprint --show${text ? ` ${text}` : ""}`
|
|
2257
2278
|
};
|
|
2258
2279
|
if (!kind || !prompts[kind]) {
|
|
2259
2280
|
console.error("Usage: scrumrun prompt <intake|study|challenge|know|context-build|context-update|vault|goal-set|sprint-add|sprint-run|backlog-add|status> [text]");
|
|
@@ -2580,6 +2601,8 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2580
2601
|
else install(target, true, { compatibility: false });
|
|
2581
2602
|
} else if (command === "sc") {
|
|
2582
2603
|
runRoot(args.slice(1));
|
|
2604
|
+
} else if (["plan", "knowledge", "rules", "review", "config"].includes(command)) {
|
|
2605
|
+
runRoot(args);
|
|
2583
2606
|
} else if (COMMAND_ALIASES[command]) {
|
|
2584
2607
|
runCompatibilityAlias(command, args.slice(1));
|
|
2585
2608
|
} else if (command === "init") {
|
|
@@ -2594,7 +2617,8 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2594
2617
|
try {
|
|
2595
2618
|
const { repair } = require(path.join(root, "lib", "commands", "repair"));
|
|
2596
2619
|
const doApply = args.includes("--apply");
|
|
2597
|
-
const
|
|
2620
|
+
const recoverOrphanTasks = args.includes("--recover-orphan-tasks");
|
|
2621
|
+
const result = repair(scrumDir, { apply: doApply, recoverOrphanTasks });
|
|
2598
2622
|
console.log(result.report);
|
|
2599
2623
|
if (!doApply && result.plan.entries.length) process.exitCode = 0;
|
|
2600
2624
|
} catch (error) {
|