scrumrun 2.7.11 → 3.0.1
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 +12 -12
- package/README.md +50 -35
- package/SPEC.md +6 -6
- package/bin/scrumrun.js +47 -35
- package/docs/COMMANDS.md +38 -37
- 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 +1 -0
- package/lib/commands/normalize-legacy.js +1 -1
- package/lib/commands/pretty-intake.js +2 -2
- package/lib/commands/render.js +9 -5
- package/lib/commands/repair.js +61 -8
- package/lib/errors.js +11 -11
- package/lib/runtime/briefing.js +2 -2
- package/lib/runtime/mutation-gateway.js +74 -0
- package/lib/runtime/orchestrator.js +94 -3
- package/lib/v2/conformance.js +13 -3
- package/package.json +1 -1
- package/templates/project/AGENTS.md +7 -5
- package/templates/shared/skills/scrumrun/SKILL.md +27 -29
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes follow Semantic Versioning.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 3.0.1 - 2026-08-31
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **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.
|
|
12
|
+
- **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.
|
|
13
|
+
|
|
14
|
+
## 3.0.0 - 2026-08-31
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Lightweight execution is now the default.** After approval, agents work directly in application files and the linked Task Markdown, then close the Run with one `scrumrun sc plan run --finalize RUN-NNN` checkpoint.
|
|
19
|
+
- **Finalization is fail-closed.** It audits the complete workspace delta, policy fingerprint, protected paths, symlink safety, scannability, secret boundary, Run ledger, and every Guardrail before completing the Task.
|
|
20
|
+
- **Guardrail proof is co-located with work.** Non-automatic rules use a compact `## Guardrail Evidence` section in the Task and are validated together at finalization; missing evidence blocks completion.
|
|
21
|
+
- **No network command loop.** Generated agent instructions prohibit repeated `npx scrumrun@latest` calls during execution. `npx` remains for one-off installation, migration, and recovery.
|
|
22
|
+
- **Strict mode remains available.** Path-scoped Mutation Gateway permits and individual Run transitions are retained for owners who explicitly request per-edit control.
|
|
23
|
+
|
|
7
24
|
## 2.7.7 - 2026-08-24
|
|
8
25
|
|
|
9
26
|
### Added
|
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,7 @@ 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.**
|
|
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
88
|
|
|
89
89
|
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
90
|
|
|
@@ -112,7 +112,7 @@ Normal read path:
|
|
|
112
112
|
4. only the canonical ids and evidence relevant to current work;
|
|
113
113
|
5. `.scrumrun/core.md` when method details or exceptional transitions are needed.
|
|
114
114
|
|
|
115
|
-
The briefing is a progressive-disclosure index, not full context. Read it first and follow its pointers to specific artifacts (`## Where to look`, `
|
|
115
|
+
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
116
|
|
|
117
117
|
Lean mode is this bounded read policy; it is not permission to omit canonical truth.
|
|
118
118
|
|
|
@@ -156,7 +156,7 @@ Intake must:
|
|
|
156
156
|
|
|
157
157
|
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
158
|
|
|
159
|
-
The agent may assert the classification explicitly with `
|
|
159
|
+
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
160
|
|
|
161
161
|
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
162
|
|
|
@@ -187,7 +187,7 @@ Rules:
|
|
|
187
187
|
- before changing application/source files, issue a short-lived path-scoped mutation permit and record the verified before/after hashes in the Run;
|
|
188
188
|
- unrecorded workspace drift, policy drift, out-of-scope paths, unsafe symlinks, new secret-like content, or unresolved obligations block validation/completion;
|
|
189
189
|
- learning proposes memory candidates after validation and never auto-confirms AI inference;
|
|
190
|
-
- record a `## Technical Summary` at completion with `
|
|
190
|
+
- record a `## Technical Summary` at completion with `scrumrun plan run --complete --summary "…"` so the next agent inherits what was actually done;
|
|
191
191
|
- complete a Sprint only when all its included Tasks meet the Sprint exit gate;
|
|
192
192
|
- do not mark work complete merely because time or token budget ended.
|
|
193
193
|
|
|
@@ -197,7 +197,7 @@ Task/Run pair mutations use an ignored durable journal under `.scrumrun/.backup/
|
|
|
197
197
|
|
|
198
198
|
### Backlog and sequencing
|
|
199
199
|
|
|
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. `
|
|
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. `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
201
|
|
|
202
202
|
### Agent identity and assignment
|
|
203
203
|
|
|
@@ -264,7 +264,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
264
264
|
|
|
265
265
|
## Command reference
|
|
266
266
|
|
|
267
|
-
###
|
|
267
|
+
### `scrumrun plan`
|
|
268
268
|
|
|
269
269
|
- `task --add|--list|--show|--run|--audit|--cancel|--retry|--next|--start [TASK-NNN]`
|
|
270
270
|
- `sprint --add|--list|--show|--start|--complete|--block`
|
|
@@ -273,7 +273,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
273
273
|
- `intake <request> [--type fix|task|feature|docs|discovery] [--preview "…"]`
|
|
274
274
|
- `challenge <question>`
|
|
275
275
|
|
|
276
|
-
###
|
|
276
|
+
### `scrumrun knowledge`
|
|
277
277
|
|
|
278
278
|
- `fact --add|--list|--show|--approve|--reject|--deprecate|--invalidate`
|
|
279
279
|
- `decision --add|--list|--show|--resolve|--deprecate|--invalidate`
|
|
@@ -284,12 +284,12 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
284
284
|
- `study <focus>`
|
|
285
285
|
- `vault --add|--list|--show|--remove|--path`
|
|
286
286
|
|
|
287
|
-
###
|
|
287
|
+
### `scrumrun rules`
|
|
288
288
|
|
|
289
289
|
- `guardrail --add|--list|--show|--retire`
|
|
290
290
|
- `reviewer --add|--list|--show|--run`
|
|
291
291
|
|
|
292
|
-
###
|
|
292
|
+
### `scrumrun review`
|
|
293
293
|
|
|
294
294
|
- `code --run`
|
|
295
295
|
- `artifact --run`
|
|
@@ -298,7 +298,7 @@ Legacy sprint plan entries normally become Tasks. History attempts become Runs w
|
|
|
298
298
|
|
|
299
299
|
Review is read-only unless fixes are separately authorized. Report findings by severity with evidence.
|
|
300
300
|
|
|
301
|
-
###
|
|
301
|
+
### `scrumrun config`
|
|
302
302
|
|
|
303
303
|
- `project --show|--language|--interaction|--approval|--quick-tasks`
|
|
304
304
|
- `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:** `
|
|
7
|
+
**Package:** `3.0.1` · **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
|
|
|
@@ -48,17 +48,17 @@ npm i -g scrumrun@latest
|
|
|
48
48
|
scrumrun update
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
`
|
|
51
|
+
Use the installed `scrumrun` command for project work. `npx` is appropriate for one-off installation, migration, or recovery only; agents must never invoke `npx scrumrun@latest` repeatedly while executing a Task, because that adds network dependency and latency to the work loop.
|
|
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
|
|
|
@@ -85,7 +85,13 @@ Explicit approval atomically materializes the required plan artifacts and always
|
|
|
85
85
|
EXECUTING → VALIDATING → LEARNING → COMPLETED | FAILED | BLOCKED
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
Every approved Task carries an `## Acceptance Criteria` section so "done" is defined before work begins
|
|
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
|
+
|
|
90
|
+
```bash
|
|
91
|
+
scrumrun plan run --finalize RUN-001
|
|
92
|
+
```
|
|
93
|
+
|
|
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.
|
|
89
95
|
|
|
90
96
|
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.
|
|
91
97
|
|
|
@@ -148,21 +154,21 @@ It is progressive disclosure: the briefing is enough for most work; the agent fo
|
|
|
148
154
|
Update the client integrations and automatically run a read-only migration preflight:
|
|
149
155
|
|
|
150
156
|
```bash
|
|
151
|
-
|
|
157
|
+
scrumrun update
|
|
152
158
|
```
|
|
153
159
|
|
|
154
160
|
This shows the source inventory, proposed mappings, and blockers without changing project data. Apply only the verified plan with:
|
|
155
161
|
|
|
156
162
|
```bash
|
|
157
|
-
|
|
163
|
+
scrumrun update --migrate
|
|
158
164
|
```
|
|
159
165
|
|
|
160
166
|
The standalone workflow remains available:
|
|
161
167
|
|
|
162
168
|
```bash
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
scrumrun migrate --to 2 --dry-run
|
|
170
|
+
scrumrun migrate --to 2 --apply
|
|
171
|
+
scrumrun migrate --to 2 --rollback
|
|
166
172
|
```
|
|
167
173
|
|
|
168
174
|
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.
|
|
@@ -170,16 +176,26 @@ Migration uses content hashes, a byte-exact ignored backup, staging validation,
|
|
|
170
176
|
For projects that already have v2 directories but contain pre-v2 Markdown records without YAML frontmatter, use the explicit repair gate:
|
|
171
177
|
|
|
172
178
|
```bash
|
|
173
|
-
|
|
174
|
-
|
|
179
|
+
scrumrun repair
|
|
180
|
+
scrumrun repair --apply
|
|
175
181
|
```
|
|
176
182
|
|
|
177
183
|
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`.
|
|
178
184
|
|
|
185
|
+
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:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
scrumrun repair --recover-orphan-tasks
|
|
189
|
+
scrumrun repair --recover-orphan-tasks --apply
|
|
190
|
+
scrumrun plan task --start TASK-144
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
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.
|
|
194
|
+
|
|
179
195
|
After migration or an integration update, verify both installed assets and project state:
|
|
180
196
|
|
|
181
197
|
```bash
|
|
182
|
-
|
|
198
|
+
scrumrun doctor codex --strict
|
|
183
199
|
```
|
|
184
200
|
|
|
185
201
|
`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.
|
|
@@ -211,7 +227,7 @@ npx scrumrun@latest doctor codex --strict
|
|
|
211
227
|
|
|
212
228
|
`guardrails.md` is canonical project policy. Active `GR-NNN` rules are evaluated into explicit `passed`, `blocked`, or `deferred` results; blocks identify the exact Guardrail and deferred checks stay visible for their execution-time gate. `config.md` contains preferences and cannot weaken policy. Duplicate/unknown Guardrails, disabled approval, and unsafe read-only paths fail conformance. `state.md`, `map.md`, context packages, and SQLite are generated navigation aids, never authority. `state.md` carries the same source fingerprint used by intake, an RFC3339 generation time, and a watch fingerprint for fast verified staleness checks.
|
|
213
229
|
|
|
214
|
-
Approved Runs persist every deferred result as an append-only obligation and bind the exact policy plus workspace baseline.
|
|
230
|
+
Approved Runs persist every deferred result as an append-only obligation and bind the exact policy plus workspace baseline. The normal final checkpoint verifies all workspace changes at once: owner/read-only scope, symlinks, new secret-like content, policy drift, and required Guardrail evidence. Completion fails closed when any verification is missing or fails. The 15-minute path-scoped Mutation Gateway remains available for teams that explicitly choose strict per-edit control.
|
|
215
231
|
|
|
216
232
|
### Owner-controlled allowlist for descriptive files
|
|
217
233
|
|
|
@@ -243,46 +259,45 @@ Rules:
|
|
|
243
259
|
|
|
244
260
|
```bash
|
|
245
261
|
# inspect the grammar
|
|
246
|
-
|
|
262
|
+
scrumrun commands
|
|
247
263
|
|
|
248
264
|
# plan without writes, then approve the emitted token
|
|
249
|
-
|
|
250
|
-
|
|
265
|
+
scrumrun plan intake "Fix pricing rounding" --type fix --preview "Rounding moved after tax calc"
|
|
266
|
+
scrumrun plan intake --approve <token>
|
|
251
267
|
|
|
252
268
|
# record what was done at completion, so the next agent inherits it
|
|
253
|
-
|
|
269
|
+
scrumrun plan run --finalize RUN-001 --summary "Moved rounding after tax calc in checkout/pricing.ts"
|
|
254
270
|
|
|
255
271
|
# auto-sequencing: surface and start the next backlog Task
|
|
256
|
-
|
|
257
|
-
|
|
272
|
+
scrumrun plan task --next
|
|
273
|
+
scrumrun plan task --start TASK-009
|
|
258
274
|
|
|
259
275
|
# authorize and record a material source mutation
|
|
260
|
-
|
|
261
|
-
|
|
276
|
+
scrumrun plan run --authorize-mutation RUN-001 --path src/pricing.ts # strict mode only
|
|
277
|
+
scrumrun plan run --record-mutation RUN-001 --permit MUT-... --note "Pricing change recorded"
|
|
262
278
|
|
|
263
279
|
# record an audit-derived Review, then resolve a persisted completion gate
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
npx scrumrun@latest sc plan run --satisfy-guardrail RUN-001 --guardrail GR-003 --review REV-001
|
|
280
|
+
scrumrun review artifact --run
|
|
281
|
+
scrumrun review artifact --record --task TASK-001 --run RUN-001 --evidence "npm test: passed"
|
|
267
282
|
|
|
268
283
|
# memory lifecycle
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
284
|
+
scrumrun knowledge insight --propose "Pricing stays in backend" --evidence src/pricing.ts
|
|
285
|
+
scrumrun knowledge insight --confirm INS-001
|
|
286
|
+
scrumrun knowledge study calculateFinalPrice
|
|
272
287
|
|
|
273
288
|
# rebuild or inspect the derived graph
|
|
274
|
-
|
|
275
|
-
|
|
289
|
+
scrumrun knowledge map --build
|
|
290
|
+
scrumrun knowledge map --show
|
|
276
291
|
|
|
277
292
|
# read a Run as a human timeline instead of raw ledger JSON
|
|
278
|
-
|
|
293
|
+
scrumrun plan run --render RUN-001
|
|
279
294
|
|
|
280
295
|
# aggregate every Run in the project (p50/p95 durations, retries, guardrail counts)
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
scrumrun plan run --stats
|
|
297
|
+
scrumrun plan run --stats --task TASK-001 --json
|
|
283
298
|
|
|
284
299
|
# preview a canonical-transaction recovery before touching disk
|
|
285
|
-
|
|
300
|
+
scrumrun config doctor --recover --dry-run
|
|
286
301
|
```
|
|
287
302
|
|
|
288
303
|
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
|
@@ -202,11 +202,11 @@ Everything through `AWAITING_APPROVAL` is read-only. It may exist in process mem
|
|
|
202
202
|
|
|
203
203
|
Approval atomically creates one Task and its first Run. If either write fails, neither may remain. Project changes after planning invalidate the token. Reusing a successfully consumed token is idempotent.
|
|
204
204
|
|
|
205
|
-
The approved Run binds the exact Guardrail-policy fingerprint and a canonical workspace baseline. Every post-approval `deferred` check becomes an append-only Guardrail obligation.
|
|
205
|
+
The approved Run binds the exact Guardrail-policy fingerprint and a canonical workspace baseline. Every post-approval `deferred` check becomes an append-only Guardrail obligation. In the normal session path, agents work directly and one final checkpoint verifies the complete baseline-to-final delta: policy freshness, read-only boundaries, symlink safety, scannability, newly introduced secret-like content, and evidence for every Guardrail. Missing or unverifiable evidence fails closed. Strict teams may opt into short-lived, path-scoped permits and per-edit recording; those commands add stronger intermediate control but are not required for normal execution.
|
|
206
206
|
|
|
207
207
|
The agent may assert the classification explicitly (`--type fix|task|feature|docs|discovery`), overriding keyword inference with validation and a stable reason. It may attach a short technical preview (`--preview`), rendered in the terminal, bound into the approval token, and stored as `## Preview` on the approved Task. A Task declares its `## Acceptance Criteria` before execution; completion is measured against them, never against elapsed time or token budget.
|
|
208
208
|
|
|
209
|
-
Run transitions synchronously update the linked Task and append exactly one structured event to the Run ledger.
|
|
209
|
+
Run transitions synchronously update the linked Task and append exactly one structured event to the Run ledger. The normal `--finalize` checkpoint writes the required validating, learning, and completed transitions together after its audit; strict mode may write them individually. Task status changes without receiving a duplicate narrative history. Completion requires a `## Technical Summary` and evidenced validation/learning. Multi-file mutations use a durable local transaction journal: `prepared` operations roll back byte-exactly after failure/interruption, while `committed` journals are verified and finalized. Ordinary audit is read-only and reports pending recovery; `doctor --recover` or retrying the approved mutation performs recovery explicitly. Entering `learning` may extract structured candidates from the Run, but extraction failure never blocks Run progress.
|
|
210
210
|
|
|
211
211
|
Backlog is a queue view of Tasks with `status: backlog`, ordered oldest-first by id. Starting a backlog Task (`--next` to surface, `--start` to promote) transitions `backlog → running`, creates the Task's first Run, re-evaluates policy, and records the agent identity. Starting is itself the explicit approval required by I-01.
|
|
212
212
|
|
|
@@ -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, nextBacklogTask, refreshErrors, refreshState, retryTask, startBacklogTask, transitionRun } = require(path.join(root, "lib", "runtime", "orchestrator"));
|
|
34
|
+
const { addPlanArtifact, 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") {
|
|
@@ -1562,6 +1562,15 @@ function executeRootRoute(route) {
|
|
|
1562
1562
|
return;
|
|
1563
1563
|
}
|
|
1564
1564
|
if (noun === "plan" && subject === "run") {
|
|
1565
|
+
if (routeArgs[0] === "--finalize") {
|
|
1566
|
+
const runId = routeArgs[1];
|
|
1567
|
+
if (!runId) throw new Error("--finalize requires RUN-NNN.");
|
|
1568
|
+
const result = finalizeRun(process.cwd(), runId, runTransitionOptions(routeArgs.slice(2)));
|
|
1569
|
+
console.log(`${result.run.id}: completed; ${result.task.id}: completed. Final session audit verified ${result.changes} change(s).`);
|
|
1570
|
+
if (result.resolved.length) console.log(`Guardrails verified: ${result.resolved.join(", ")}.`);
|
|
1571
|
+
if (result.learning && result.learning.created.length) console.log(`Learning candidates: ${result.learning.created.join(", ")}.`);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1565
1574
|
if (routeArgs[0] === "--authorize-mutation") {
|
|
1566
1575
|
const paths = optionValues(routeArgs.slice(2), "--path");
|
|
1567
1576
|
const result = authorizeMutation(process.cwd(), routeArgs[1], paths);
|
|
@@ -1680,7 +1689,7 @@ function runRoot(parts) {
|
|
|
1680
1689
|
|
|
1681
1690
|
function runCompatibilityAlias(alias, parts) {
|
|
1682
1691
|
const route = resolveAlias(alias, parts);
|
|
1683
|
-
console.warn(`Deprecated: ${alias} now executes
|
|
1692
|
+
console.warn(`Deprecated: ${alias} now executes scrumrun ${route.noun} ${route.subject}.`);
|
|
1684
1693
|
if (route.note) console.warn(route.note);
|
|
1685
1694
|
if (alias === "sc-backlog") return runBacklog(parts);
|
|
1686
1695
|
if (alias !== "sc-init") chdirToProjectRoot();
|
|
@@ -1696,7 +1705,7 @@ function printCore({ pathOnly = false, promptOnly = false } = {}) {
|
|
|
1696
1705
|
if (promptOnly) {
|
|
1697
1706
|
console.log(`Read AGENTS.md, .scrumrun/guardrails.md, and .scrumrun/state.md first.
|
|
1698
1707
|
Follow ScrumRun 2.0 and load only the canonical ids/evidence relevant to the request.
|
|
1699
|
-
|
|
1708
|
+
Use the installed CLI as scrumrun <noun> <subject> <action>; /sc is only a client shortcut.
|
|
1700
1709
|
Keep intake read-only; do not create a Task or Run until explicit approval.`);
|
|
1701
1710
|
return;
|
|
1702
1711
|
}
|
|
@@ -2171,7 +2180,7 @@ function statusProject() {
|
|
|
2171
2180
|
}
|
|
2172
2181
|
console.log("");
|
|
2173
2182
|
console.log(`Migration record: ${fs.existsSync(path.join(scrumDir, ".migration", "v1-to-v2", "manifest.json")) ? "v1-to-v2 applied" : "not applicable / native v2"}`);
|
|
2174
|
-
console.log(`Canonical command:
|
|
2183
|
+
console.log(`Canonical command: scrumrun <noun> <subject> <action>`);
|
|
2175
2184
|
return;
|
|
2176
2185
|
}
|
|
2177
2186
|
const required = [
|
|
@@ -2227,24 +2236,24 @@ function promptCommand(parts) {
|
|
|
2227
2236
|
const kind = parts[0];
|
|
2228
2237
|
const text = joinText(parts.slice(1));
|
|
2229
2238
|
const prompts = {
|
|
2230
|
-
intake:
|
|
2231
|
-
study:
|
|
2232
|
-
challenge:
|
|
2233
|
-
know:
|
|
2234
|
-
"context-build":
|
|
2235
|
-
"context-update":
|
|
2236
|
-
"context-show":
|
|
2237
|
-
context:
|
|
2238
|
-
vault:
|
|
2239
|
-
"goal-set":
|
|
2240
|
-
"goal-new":
|
|
2241
|
-
goal:
|
|
2242
|
-
"sprint-add":
|
|
2243
|
-
"sprint-new":
|
|
2244
|
-
"sprint-run":
|
|
2245
|
-
"backlog-add":
|
|
2246
|
-
backlog:
|
|
2247
|
-
status:
|
|
2239
|
+
intake: `scrumrun plan intake ${text}`.trim(),
|
|
2240
|
+
study: `scrumrun knowledge study${text ? ` ${text}` : ""}`,
|
|
2241
|
+
challenge: `scrumrun plan challenge ${text}`.trim(),
|
|
2242
|
+
know: `scrumrun knowledge fact --add ${text}`.trim(),
|
|
2243
|
+
"context-build": `scrumrun knowledge context --build${text ? ` ${text}` : ""}`,
|
|
2244
|
+
"context-update": `scrumrun knowledge context --update${text ? ` ${text}` : ""}`,
|
|
2245
|
+
"context-show": `scrumrun knowledge context --show${text ? ` ${text}` : ""}`,
|
|
2246
|
+
context: `scrumrun knowledge context ${text}`.trim(),
|
|
2247
|
+
vault: `scrumrun knowledge vault ${text}`.trim(),
|
|
2248
|
+
"goal-set": `scrumrun plan feature --add ${text}`.trim(),
|
|
2249
|
+
"goal-new": `scrumrun plan feature --add ${text}`.trim(),
|
|
2250
|
+
goal: `scrumrun plan feature --add ${text}`.trim(),
|
|
2251
|
+
"sprint-add": `scrumrun plan sprint --add ${text}`.trim(),
|
|
2252
|
+
"sprint-new": `scrumrun plan sprint --add ${text}`.trim(),
|
|
2253
|
+
"sprint-run": `scrumrun plan task --run ${text}`.trim(),
|
|
2254
|
+
"backlog-add": `scrumrun plan task --add ${text} --status backlog`.trim(),
|
|
2255
|
+
backlog: `scrumrun plan task --add ${text} --status backlog`.trim(),
|
|
2256
|
+
status: `scrumrun plan sprint --show${text ? ` ${text}` : ""}`
|
|
2248
2257
|
};
|
|
2249
2258
|
if (!kind || !prompts[kind]) {
|
|
2250
2259
|
console.error("Usage: scrumrun prompt <intake|study|challenge|know|context-build|context-update|vault|goal-set|sprint-add|sprint-run|backlog-add|status> [text]");
|
|
@@ -2571,6 +2580,8 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2571
2580
|
else install(target, true, { compatibility: false });
|
|
2572
2581
|
} else if (command === "sc") {
|
|
2573
2582
|
runRoot(args.slice(1));
|
|
2583
|
+
} else if (["plan", "knowledge", "rules", "review", "config"].includes(command)) {
|
|
2584
|
+
runRoot(args);
|
|
2574
2585
|
} else if (COMMAND_ALIASES[command]) {
|
|
2575
2586
|
runCompatibilityAlias(command, args.slice(1));
|
|
2576
2587
|
} else if (command === "init") {
|
|
@@ -2585,7 +2596,8 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2585
2596
|
try {
|
|
2586
2597
|
const { repair } = require(path.join(root, "lib", "commands", "repair"));
|
|
2587
2598
|
const doApply = args.includes("--apply");
|
|
2588
|
-
const
|
|
2599
|
+
const recoverOrphanTasks = args.includes("--recover-orphan-tasks");
|
|
2600
|
+
const result = repair(scrumDir, { apply: doApply, recoverOrphanTasks });
|
|
2589
2601
|
console.log(result.report);
|
|
2590
2602
|
if (!doApply && result.plan.entries.length) process.exitCode = 0;
|
|
2591
2603
|
} catch (error) {
|