scrumrun 3.1.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ All notable changes follow Semantic Versioning.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 4.0.0 - 2026-08-31
8
+
9
+ ### Changed
10
+
11
+ - **Simple Markdown model.** Core, Guardrails, Knowledge, Feature, Sprint, Task, Run, and Backlog are one local Markdown graph connected by stable IDs and relative links. Derived cache/index data is optional and never required for normal work.
12
+ - **Execution-first.** An approved Task continues through discover → implement → verify → fix → verify. Intermediate inventories, progress reports, and discovered in-scope gaps are internal work, never a valid stopping point or Follow-up.
13
+ - **Flexible Task bodies.** Tasks preserve arbitrary owner frontmatter and sections. `## Done when` and `## Completion` are the packaged minimal convention; project Guardrails may require extra sections only for affected Tasks.
14
+ - **Human status vocabulary.** `in_progress` is accepted as a Task status. A Markdown-first Task neither needs a Run nor must agree with historical Run state.
15
+ - **Runs are optional.** A Run may record a Task or a Sprint execution, but no Run, ledger, permit, or CLI state transition can block daily delivery.
16
+
17
+ ### Safety
18
+
19
+ - **Sealed Markdown policy.** Fresh and refreshed projects pin Core and Guardrail fingerprints. Agents do not edit policy during product work; owner-reviewed policy changes use `scrumrun update --project --seal-policy`. Strict doctor/release audits detect policy drift at the edge, not during every edit.
20
+
7
21
  ## 3.1.2 - 2026-08-31
8
22
 
9
23
  ### Fixed
package/CORE.md CHANGED
@@ -84,13 +84,21 @@ 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
- **Markdown is the normal runtime.** After explicit approval, work directly in source files and relevant `.scrumrun/` Markdown. A Task is free to be created, refined, started, completed, and handed off in Markdown; a Run is optional audit context, never a state machine that can prevent daily work. Update the Task's scope, Acceptance Criteria, Technical Summary, and Follow-ups directly. Do not use `npx scrumrun@latest` or normal `scrumrun plan/run` commands during execution.
87
+ **Markdown is the normal runtime.** After explicit approval, work directly in source files and relevant `.scrumrun/` Markdown. A Task is free to be created, refined, started, completed, and handed off in Markdown; a Run is optional audit context, never a state machine that can prevent daily work. Update the Task's scope, Done when, Completion, and Follow-ups directly. Do not use `npx scrumrun@latest` or normal `scrumrun plan/run` commands during execution.
88
+
89
+ **Execution is continuous.** Once the owner approves a Task, implement it through its delivery contract before replying. Keep using tools and editing files through the full loop: discover → implement → verify → fix → verify. A progress report is allowed only when the owner asks for status, and it must be followed immediately by more execution in the same workflow; it is never an endpoint. Do not stop to give an inventory, a progress report, a decomposition, or a remaining-work list: those are internal steps, not a deliverable. A discovery of missing code, literals, tests, migrations, or configuration inside the approved contract is required work to implement now — it cannot become a report, a partial checker, a “next step”, or a Follow-up. Stop only for an owner decision, external access, an explicit Guardrail, a secret/security risk, destructive work without approval, or an unmet required delivery criterion. A Task's `## Done when` is short and observable; `## Follow-ups` contains only work outside that contract. Never move unfinished contract work to Follow-ups without explicit owner approval.
90
+
91
+ **Verification must cover the claim.** Never claim that a Task condition is verified merely because a narrower check passes. If the request is “no visible hardcoded literals”, a locale-key parity checker alone is insufficient: scan the relevant views for literals, replace every result in scope, then re-run both the scan and the build. The same rule applies to every delivery claim.
88
92
 
89
93
  **The CLI is maintenance, not a work gate.** Use it for `init`, `update --project`, `migrate`, `repair`, `doctor`, reports, and release checks. Strict per-edit permits and ledger finalization remain available only when the owner asks for that audit level. Missing/invalid Runs, old status vocabulary, stale projections, and optional tests are warnings to reconcile in Markdown — never an automatic blocker.
90
94
 
91
- **Block only on real constraints.** An agent must stop for an explicit active Guardrail, secret/security risk, destructive action without approval, or an unmet required Acceptance Criterion. It must not manufacture a failed/blocked Run because optional E2E coverage, an optional reviewer, or a non-required environment is unavailable; record meaningful gaps in `## Follow-ups` or a risk note.
95
+ **Block only on real constraints.** An agent must stop for an explicit active Guardrail, secret/security risk, destructive action without approval, or an unmet required Done when item. It must not manufacture a failed/blocked Run because optional E2E coverage, an optional reviewer, or a non-required environment is unavailable; record meaningful gaps in `## Follow-ups` or a risk note.
96
+
97
+ **Normal operation never mutates Run state through the CLI.** Do not call `plan run --fail|--block|--retry|--finalize|--complete|--validate` or `plan task --start` in daily work. Those are owner-requested strict audit tools only. When a legacy Run already has the wrong administrative outcome, preserve it as history and correct the delivery record directly in the Task's Completion and Follow-ups.
98
+
99
+ **Policy is sealed at the edge.** `core.md` is the universal execution contract and `guardrails.md` is project policy. Never edit either while delivering product work. A policy change requires an explicit owner request; after review, `scrumrun update --project --seal-policy` records fresh fingerprints. Daily work stays Markdown-only; `doctor --strict` and release audit policy fingerprints, canonical guardrails, and code checks at the boundary.
92
100
 
93
- **Normal operation never mutates Run state through the CLI.** Do not call `plan run --fail|--block|--retry|--finalize|--complete|--validate` or `plan task --start` in daily work. Those are owner-requested strict audit tools only. When a legacy Run already has the wrong administrative outcome, preserve it as history and correct the delivery record directly in the Task's Technical Summary and Follow-ups.
101
+ **Markdown relations are the graph.** Every artifact has a stable ID. Use small frontmatter links such as `sprint: SPRINT-012`, `feature: FEAT-003`, and `depends_on: [TASK-151, DEC-008]`, plus a human-readable `## Related` section with relative links. Preserve all unknown frontmatter and all owner-defined sections. A Guardrail may require a Task section such as `## Migration Plan`, `## Rollback`, or `## Guardrail Evidence`; add it only to the affected Task and keep it until the rule is satisfied.
94
102
 
95
103
  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.
96
104
 
@@ -176,7 +184,7 @@ understand → approve → work → validate required criteria → hand off
176
184
 
177
185
  Rules:
178
186
 
179
- - a Task carries the intended scope, `## Acceptance Criteria`, `## Technical Summary`, and relevant `## Follow-ups`;
187
+ - a Task carries intended scope, a short `## Done when` contract, `## Completion`, and relevant `## Follow-ups`;
180
188
  - validation matches risk and acceptance criteria; tests, reviews, and environments are gates only when explicitly required by the owner, the Task, or an active Guardrail;
181
189
  - direct Markdown workflow never blocks on Run linkage, status syntax, stale generated views, or missing optional coverage. If an optional check matters, record it as a follow-up/risk instead of fabricating failure;
182
190
  - configured reviews run only when a Guardrail requires one;
@@ -184,7 +192,7 @@ Rules:
184
192
  - strict permits, workspace-drift checks, and append-only Guardrail obligations apply only to that optional strict audit path;
185
193
  - learning proposes memory candidates when work reveals reusable context and never auto-confirms AI inference;
186
194
  - complete a Sprint only when its included Tasks meet its real exit gate;
187
- - do not mark work complete merely because time or token budget ended.
195
+ - do not mark work complete merely because time or token budget ended, and do not stop an approved Task merely to report intermediate progress.
188
196
 
189
197
  Canonical mutations are schema-validated, lossless, and atomic. Preserve unknown fields, prose, and unrelated owner edits. A failed mutation must leave canonical state unchanged or recoverable.
190
198
 
package/README.md CHANGED
@@ -4,30 +4,33 @@
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.1.2` · **Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
7
+ **Package:** `4.0.0` · **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
 
11
11
  ## The model
12
12
 
13
13
  ```text
14
- Feature = why the initiative matters
15
- Task = what atomic work must be done
16
- Sprint = when Tasks are grouped as a timebox/batch
17
- Run = how one concrete attempt happened
18
- Memory = what the project learned and why
14
+ Core = how the agent works
15
+ Guardrails = rules that cannot be broken
16
+ Knowledge = what the project knows and why
17
+ Backlog = provisioned Tasks not yet started
18
+ Feature = why a larger initiative exists
19
+ Sprint = a feature, fix, or maintenance delivery grouping Tasks
20
+ Task = concrete work, independent or in a Sprint
21
+ Run = optional record of what happened while executing a Task/Sprint
19
22
  ```
20
23
 
21
24
  ```text
22
- FEAT-003
25
+ SPRINT-012 (type: fix)
23
26
  └── TASK-018
24
- ├── executed_byRUN-044
25
- ├── included_inSPRINT-012
26
- ├── constrained_byDEC-018
27
- └── generatedINS-041
27
+ ├── featureFEAT-003
28
+ ├── depends_onTASK-014, DEC-018
29
+ ├── guardrailsGR-004
30
+ └── runRUN-044 (optional)
28
31
  ```
29
32
 
30
- A Task does not need a Sprint. A retry creates a new Run. A fix is a Task with `type: fix`; backlog is a view of backlog Tasks.
33
+ A Task does not need a Sprint. A Sprint may be `feature`, `fix`, or `maintenance`. A Run is optional and may document a Task or Sprint. Backlog is simply Tasks with `status: backlog`.
31
34
 
32
35
  See [`docs/SCHEMA.md`](docs/SCHEMA.md) for the generated executable contract and [`docs/ENTITY-MODEL.md`](docs/ENTITY-MODEL.md) for the conceptual guide.
33
36
 
@@ -79,15 +82,15 @@ RECEIVED → CONTEXTUALIZING → POLICY → RISK → CLASSIFICATION
79
82
 
80
83
  The agent may assert the classification (`--type fix|task|feature|docs|discovery`) and attach a short technical preview (`--preview "…"`), rendered with color in the terminal before any Task exists. Nothing canonical is persisted before approval.
81
84
 
82
- Explicit approval authorizes work. In 3.1, the daily runtime is the `.scrumrun/` folder: the agent creates or refines the relevant Task Markdown, works in code, and leaves a short handoff. Feature, Sprint, and Run are optional context, not prerequisites. A structured CLI audit path remains available when a team wants it.
85
+ Explicit approval authorizes work. In 4.0, the daily runtime is the `.scrumrun/` folder: the agent creates or refines the relevant Task Markdown, works in code, and leaves a short handoff. Feature, Sprint, and Run are optional context, not prerequisites. A structured CLI audit path remains available only at maintenance/release edges.
83
86
 
84
87
  ```text
85
88
  EXECUTING → VALIDATING → LEARNING → COMPLETED | FAILED | BLOCKED
86
89
  ```
87
90
 
88
- Every Task carries `## Acceptance Criteria` so "done" is defined before work begins. After approval, the agent works directly in code and Task Markdown, updating `## Technical Summary` and `## Follow-ups`. The normal close is simply the documented Task handoff no CLI transition is required.
91
+ Every Task carries a short `## Done when` delivery contract. After approval, the agent works directly in code and Task Markdown until that contract is delivered: it keeps the full discover → implement → verify → fix → verify loop running. A report is allowed only when you ask for it and never ends execution. The normal close is a concise `## Completion`; `## Follow-ups` may only contain work outside the agreed contract. No CLI transition is required.
89
92
 
90
- Guardrails still apply. An agent stops only for an explicit active Guardrail, a secret/security risk, destructive work without approval, or an unmet required Acceptance Criterion. Tests, reviews, and environments are gates only when the owner, Acceptance Criteria, or a Guardrail explicitly requires them. Optional missing E2E coverage is a follow-up/risk, not a failed Task.
93
+ Guardrails still apply. An agent stops only for an explicit active Guardrail, a secret/security risk, destructive work without approval, or an unmet required delivery criterion. Tests, reviews, and environments are gates only when the owner, `Done when`, or a Guardrail explicitly requires them. Optional missing E2E coverage is a follow-up/risk, not a failed Task.
91
94
 
92
95
  Use the CLI at the edges, where its safety is valuable:
93
96
 
@@ -99,6 +102,10 @@ scrumrun repair --recover-orphan-tasks --apply
99
102
  scrumrun review release --run
100
103
  ```
101
104
 
105
+ `core.md` and `guardrails.md` are sealed Markdown policy. Agents never edit them during normal product work. An owner-requested policy change is reviewed and then sealed explicitly with `scrumrun update --project --seal-policy`; `doctor --strict` and release checks detect later policy drift.
106
+
107
+ Relations are plain, offline Markdown: stable IDs in frontmatter (`sprint: SPRINT-012`, `depends_on: [TASK-014, DEC-018]`) and relative links in `## Related`. Task Markdown is intentionally extensible: a Guardrail can require `## Migration Plan`, `## Rollback`, or `## Guardrail Evidence` only where relevant, and ScrumRun preserves every unknown section.
108
+
102
109
  `update --project` refreshes packaged `core.md` and recognized generated `AGENTS.md` with a local byte-exact backup before replacing them. The CLI can still generate/validate Task, Feature, Sprint, and Run records when desired, but it must never become a routine blocker.
103
110
 
104
111
  For extra protection, CLI Task start/retry and every Run state transition require `--strict`. This prevents accidental administrative failures in the normal Markdown-first workflow.
@@ -161,12 +168,18 @@ It is progressive disclosure: the briefing is enough for most work; the agent fo
161
168
 
162
169
  ## Migrating an ongoing v1 project
163
170
 
164
- Update the client integrations. For an existing project, refresh the Markdown-first guidance explicitly:
171
+ Update the client integrations. For an existing project, refresh the execution-first guidance explicitly:
165
172
 
166
173
  ```bash
167
174
  scrumrun update --project
168
175
  ```
169
176
 
177
+ If you intentionally changed project Guardrails after owner review, seal the reviewed Markdown policy once:
178
+
179
+ ```bash
180
+ scrumrun update --project --seal-policy
181
+ ```
182
+
170
183
  This shows the source inventory, proposed mappings, and blockers without changing project data. Apply only the verified plan with:
171
184
 
172
185
  ```bash
package/SPEC.md CHANGED
@@ -83,6 +83,8 @@ method: 2.0.0
83
83
 
84
84
  IDs, filenames, kind, status, real ISO dates, and method version must agree. Unknown fields and authored prose are preserved. Duplicate fields, malformed frontmatter, unsafe paths, and symlinked canonical paths are invalid.
85
85
 
86
+ Relationship lists are valid local frontmatter, for example `depends_on: [TASK-014, DEC-018]` and `guardrails: [GR-004]`. Human-readable `## Related` links use relative Markdown paths. These local IDs and links are the canonical graph; generated indexes only accelerate retrieval.
87
+
86
88
  A Task may carry an optional `assignee` scalar recording the agent identity (`SCRUMRUN_AGENT` or `config.md` `Agent Identity`) that owns the work. It is descriptive metadata, never a competing authority: it does not change status transitions or block conformance.
87
89
 
88
90
  ### 3.2 Stable identifiers
@@ -200,13 +202,15 @@ RECEIVED
200
202
 
201
203
  Everything through `AWAITING_APPROVAL` is read-only. It may exist in process memory or ignored cache only. A valid approval token binds the normalized request, policy result, classification, risk, issuance time, canonical context fingerprint, and complete workspace fingerprint. Canonical or source drift after planning invalidates approval.
202
204
 
203
- Approval authorizes work after the read-only planning pass. In Markdown-first mode, a Task and optional Run may be created or updated directly; their absence or imperfect administrative metadata never prevents approved work. The CLI's atomic Task/Run creation remains an optional strict/audit path. Tests, reviews, and environments are completion gates only when explicitly required by the owner, the Task's Acceptance Criteria, or an active Guardrail; missing optional coverage is a documented follow-up/risk, not a failure by itself.
205
+ Approval authorizes work after the read-only planning pass. In Markdown-first mode, a Task and optional Run may be created or updated directly; their absence or imperfect administrative metadata never prevents approved work. The CLI's atomic Task/Run creation remains an optional strict/audit path. Tests, reviews, and environments are completion gates only when explicitly required by the owner, the Task's `## Done when` contract, or an active Guardrail; missing optional coverage is a documented follow-up/risk, not a failure by itself.
206
+
207
+ An approved Task executes continuously to its delivery contract. An agent must not end a work turn merely to provide inventory, decomposition, progress, or a list of remaining implementation work. Those are internal execution steps. It may stop only for an owner decision, external access, an active Guardrail, secret/security risk, destructive work without approval, or an unmet required contract item. `## Follow-ups` may contain only work outside `## Done when`; moving required work there requires explicit owner approval.
204
208
 
205
209
  When a structured Run is explicitly chosen, it binds the exact Guardrail-policy fingerprint and workspace baseline. Strict audit then verifies the complete delta: policy freshness, read-only boundaries, symlink safety, scannability, newly introduced secret-like content, and evidence for every Guardrail. Strict teams may opt into short-lived, path-scoped permits and per-edit recording. This audit path is never a prerequisite for ordinary Markdown-first execution.
206
210
 
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.
211
+ 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 normally declares a concise `## Done when` contract before execution, but owner-defined Markdown sections remain valid; completion is measured against the agreed delivery contract, never against elapsed time or token budget.
208
212
 
209
- When a structured Run is used, CLI transitions synchronously update the linked Task and append one event to its ledger. This is an optional audit path, not daily operational authority. Markdown-first completion records the Acceptance Criteria, Technical Summary, validation evidence, and Follow-ups directly on the Task. Multi-file CLI mutations use a durable local transaction journal; `doctor --recover` and `repair` remain explicit maintenance operations. Entering learning may extract candidates, but no administrative artifact failure blocks approved work.
213
+ When a structured Run is used, CLI transitions synchronously update the linked Task and append one event to its ledger. This is an optional audit path, not daily operational authority. Markdown-first completion records the Done when contract, Completion, validation evidence, and Follow-ups directly on the Task. Multi-file CLI mutations use a durable local transaction journal; `doctor --recover` and `repair` remain explicit maintenance operations. Entering learning may extract candidates, but no administrative artifact failure blocks approved work.
210
214
 
211
215
  Backlog is a queue view of intentionally parked Tasks, ordered oldest-first by id. CLI `--next`/`--start` helpers may create a structured Run when wanted, but an explicit owner approval is the only daily-work start gate.
212
216
 
package/bin/scrumrun.js CHANGED
@@ -39,6 +39,7 @@ const { indexPath, indexStatus, mapStatus, queryIndex, rebuildIndex, writeMap }
39
39
  const { auditProject } = require(path.join(root, "lib", "v2", "conformance"));
40
40
  const { recoverPendingTransactions, previewPendingRecovery } = require(path.join(root, "lib", "v2", "transaction"));
41
41
  const { containsSecret } = require(path.join(root, "lib", "security", "secrets"));
42
+ const { sealPolicyIntegrity } = require(path.join(root, "lib", "runtime", "policy-integrity"));
42
43
 
43
44
  const COMMANDS = ["sc"];
44
45
  const COMPATIBILITY_COMMANDS = Object.keys(COMMAND_ALIASES);
@@ -58,7 +59,7 @@ Usage:
58
59
  scrumrun <noun> <subject> <action> [args]
59
60
  scrumrun sc <noun> <subject> <action> [args] # compatibility alias
60
61
  scrumrun install [all|codex|opencode|claude] [--force]
61
- scrumrun update [all|codex|opencode|claude] [--project] [--migrate] [--verbose]
62
+ scrumrun update [all|codex|opencode|claude] [--project] [--seal-policy] [--migrate] [--verbose]
62
63
  scrumrun init [--local|--shared] [--lean] [--no-agent-hint] [--force]
63
64
  scrumrun status
64
65
  scrumrun core [--path|--prompt]
@@ -380,10 +381,13 @@ function refreshProjectGuidance(cwd = process.cwd()) {
380
381
  } else {
381
382
  results.push({ status: "skipped", dest: `${agentsFile} (not recognized as ScrumRun-generated)` });
382
383
  }
384
+ const marker = path.join(cwd, ".scrumrun", "method.json");
385
+ const sealed = writeFile(marker, sealPolicyIntegrity(path.join(cwd, ".scrumrun")), { backup: true });
386
+ results.push({ status: sealed.changed ? "updated" : "skipped", dest: marker, backup: sealed.backup });
383
387
  return results;
384
388
  }
385
389
 
386
- function updateInstallation(target, { migrate = false, project = false, verbose = false } = {}) {
390
+ function updateInstallation(target, { migrate = false, project = false, sealPolicy = false, verbose = false } = {}) {
387
391
  installVerbose = verbose;
388
392
  installSummary.cleaned = 0;
389
393
  installSummary.written = 0;
@@ -391,7 +395,14 @@ function updateInstallation(target, { migrate = false, project = false, verbose
391
395
  installSummary.targets.length = 0;
392
396
  const migration = migrate ? migrationPreflightOnUpdate({ apply: true }) : { status: "skipped" };
393
397
  install(target, true, { compatibility: true });
398
+ if (sealPolicy && !project) throw new Error("`--seal-policy` requires `--project` so the owner-reviewed project policy is explicit.");
394
399
  const projectResults = project ? refreshProjectGuidance() : [];
400
+ if (sealPolicy && project) {
401
+ const scrumDir = path.join(process.cwd(), ".scrumrun");
402
+ const marker = path.join(scrumDir, "method.json");
403
+ const sealed = writeFile(marker, sealPolicyIntegrity(scrumDir, { includeGuardrails: true }), { backup: true });
404
+ projectResults.push({ status: sealed.changed ? "updated" : "skipped", dest: marker, backup: sealed.backup });
405
+ }
395
406
  if (migrate && v2Project()) {
396
407
  try {
397
408
  refreshState(path.join(process.cwd(), ".scrumrun"));
@@ -1706,7 +1717,12 @@ function executeRootRoute(route) {
1706
1717
  }
1707
1718
  if (noun === "config" && subject === "update") {
1708
1719
  const target = ["all", "codex", "opencode", "claude"].includes(routeArgs[0]) ? routeArgs[0] : "all";
1709
- return updateInstallation(target, { migrate: !routeArgs.includes("--no-migrate"), verbose: routeArgs.includes("--verbose") });
1720
+ return updateInstallation(target, {
1721
+ migrate: routeArgs.includes("--migrate"),
1722
+ project: routeArgs.includes("--project"),
1723
+ sealPolicy: routeArgs.includes("--seal-policy"),
1724
+ verbose: routeArgs.includes("--verbose")
1725
+ });
1710
1726
  }
1711
1727
  if (noun === "config" && subject === "init") {
1712
1728
  const localMode = routeArgs.includes("--local");
@@ -2322,6 +2338,8 @@ function promptCommand(parts) {
2322
2338
 
2323
2339
  function initProject({ force, mode, agentHint, lean }) {
2324
2340
  const cwd = process.cwd();
2341
+ const marker = path.join(cwd, ".scrumrun", "method.json");
2342
+ const markerExisted = fs.existsSync(marker);
2325
2343
  const vars = {
2326
2344
  PROJECT_NAME: path.basename(cwd),
2327
2345
  DATE: new Date().toISOString().slice(0, 10)
@@ -2332,6 +2350,10 @@ function initProject({ force, mode, agentHint, lean }) {
2332
2350
 
2333
2351
  results.push(...copyDir(path.join(projectTemplate, ".scrumrun"), path.join(cwd, ".scrumrun"), { force, vars }));
2334
2352
  results.push(copyFile(path.join(root, "CORE.md"), path.join(cwd, ".scrumrun", "core.md"), { force, vars }));
2353
+ if (force || !markerExisted) {
2354
+ const sealed = writeFile(marker, sealPolicyIntegrity(path.join(cwd, ".scrumrun"), { includeGuardrails: true }), { backup: false });
2355
+ results.push({ status: sealed.changed ? "written" : "skipped", dest: marker, backup: sealed.backup });
2356
+ }
2335
2357
  results.push(ensureProjectIgnore(cwd));
2336
2358
 
2337
2359
  if (mode === "shared" || agentHint) {
@@ -2611,8 +2633,9 @@ function doctor(target = "all", { compatibility = false, strict = false, recover
2611
2633
  console.log(`miss ScrumRun project audit: ${scrumDir}`);
2612
2634
  } else {
2613
2635
  const audit = auditProject(process.cwd());
2614
- ok = ok && audit.passed && audit.findings.length === 0;
2615
- console.log(`${audit.passed && audit.findings.length === 0 ? "ok " : "fail"} ScrumRun project audit: ${audit.findings.length} finding(s)`);
2636
+ const blocking = audit.findings.filter((item) => ["critical", "high"].includes(item.severity));
2637
+ ok = ok && audit.passed && blocking.length === 0;
2638
+ console.log(`${audit.passed && blocking.length === 0 ? "ok " : "fail"} ScrumRun project audit: ${audit.findings.length} finding(s)`);
2616
2639
  for (const item of audit.findings) console.log(` ${item.severity} ${item.code}: ${item.message}`);
2617
2640
  }
2618
2641
  }
@@ -2633,7 +2656,7 @@ if (!command || command === "--help" || command === "-h") {
2633
2656
  console.log(`ScrumRun ${version}`);
2634
2657
  } else if (command === "install" || command === "update") {
2635
2658
  const target = ["all", "codex", "opencode", "claude"].includes(args[1]) ? args[1] : "all";
2636
- if (command === "update") updateInstallation(target, { migrate: args.includes("--migrate"), project: args.includes("--project"), verbose: args.includes("--verbose") });
2659
+ if (command === "update") updateInstallation(target, { migrate: args.includes("--migrate"), project: args.includes("--project"), sealPolicy: args.includes("--seal-policy"), verbose: args.includes("--verbose") });
2637
2660
  else install(target, true, { compatibility: false });
2638
2661
  } else if (command === "sc") {
2639
2662
  runRoot(args.slice(1));
package/docs/COMMANDS.md CHANGED
@@ -1,4 +1,4 @@
1
- # ScrumRun 3.1 Command Reference
1
+ # ScrumRun 4.0 Command Reference
2
2
 
3
3
  The canonical grammar is:
4
4
 
@@ -27,13 +27,13 @@ scrumrun plan run --satisfy-guardrail RUN-NNN --guardrail GR-NNN [typed evidence
27
27
  scrumrun plan challenge <question>
28
28
  ```
29
29
 
30
- Normal execution is Markdown-first: after approval, work in code and the relevant Task Markdown, then record the Technical Summary and any Follow-ups directly. A Run/`--finalize` checkpoint is optional strict audit, never a prerequisite. Mutation permits are available only for explicitly requested strict mode.
30
+ Normal execution is Markdown-first: after approval, work in code and the relevant Task Markdown through discover → implement → verify → fix → verify, then record `## Completion` and any genuinely out-of-scope Follow-ups directly. A Run/`--finalize` checkpoint is optional strict audit, never a prerequisite. Mutation permits are available only for explicitly requested strict mode.
31
31
 
32
32
  The CLI refuses Task start/retry and all Run state changes unless `--strict` is present. This prevents an agent from accidentally manufacturing a failed/blocked retry during normal work; `--strict` is for an owner-requested audit only.
33
33
 
34
34
  `--amend` is an optional structured helper. The Markdown-first workflow may adjust Task/Feature/Sprint content directly, preserving a useful handoff. Use the CLI when atomic relation synchronization or machine audit is valuable; do not let status vocabulary or missing relations stop approved work.
35
35
 
36
- Every new Task starts with a `## Validation Scope`: only checks explicitly required by the owner, Acceptance Criteria, or an active Guardrail block completion. Missing optional E2E, integration, or review coverage belongs in a follow-up/risk note; it must not be used to mark the Run failed.
36
+ Every new Task starts with `## Done when` and `## Validation Scope`: only checks explicitly required by the owner, Done when contract, or an active Guardrail block completion. A discovered in-scope gap remains work to implement, not a status report or Follow-up. Missing optional E2E, integration, or review coverage belongs in a follow-up/risk note; it must not be used to mark the Run failed.
37
37
 
38
38
  ## What can be changed
39
39
 
@@ -82,14 +82,14 @@ scrumrun review release --run
82
82
  ```text
83
83
  scrumrun config project --show|--language|--interaction|--approval|--quick-tasks
84
84
  scrumrun config init --local|--shared|--lean|--no-agent-hint|--force
85
- scrumrun config update [all|codex|opencode|claude] [--project] [--migrate]
85
+ scrumrun config update [all|codex|opencode|claude] [--project] [--seal-policy] [--migrate]
86
86
  scrumrun config migrate --to 2 --dry-run|--apply|--rollback
87
87
  scrumrun config doctor [all|codex|opencode|claude] [--strict] [--recover]
88
88
  scrumrun config uninstall --force
89
89
  scrumrun config help <topic>
90
90
  ```
91
91
 
92
- Top-level CLI aliases (`init`, `update`, `migrate`, `doctor`, `uninstall`, `status`) remain available for shell automation. `update --project` refreshes the packaged Markdown-first Core and recognized generated agent instructions with local backup; ordinary update does not inspect migrations, while `--migrate` explicitly does so and applies the verified plan.
92
+ Top-level CLI aliases (`init`, `update`, `migrate`, `doctor`, `uninstall`, `status`) remain available for shell automation. `update --project` refreshes the packaged execution-first Core and recognized generated agent instructions with local backup. `update --project --seal-policy` is the owner-reviewed maintenance action that pins fresh Core/Guardrail fingerprints. Ordinary update does not inspect migrations, while `--migrate` explicitly does so and applies the verified plan.
93
93
 
94
94
  Run transitions accept typed evidence through `--command`, `--test`, `--file`, `--review`, `--decision`, `--insight`, `--risk`, or generic `--evidence kind:value`. `doctor --recover` is an explicit write that resolves only safe pending kernel transactions; doctor without it remains read-only.
95
95
 
@@ -1,4 +1,4 @@
1
- # ScrumRun 2.0 Entity Model
1
+ # ScrumRun 4.0 Markdown Model
2
2
 
3
3
  This document explains the model. Exact ids, directories, initial states, transitions, structural cardinalities, truth ownership, and authority boundaries are generated from `lib/v2/schema.js` into [`SCHEMA.md`](SCHEMA.md). Do not maintain another hand-written schema table here.
4
4
 
@@ -6,32 +6,35 @@ This document explains the model. Exact ids, directories, initial states, transi
6
6
 
7
7
  | Entity | Question | Lifetime |
8
8
  |---|---|---|
9
+ | Core | How must the agent work? | Stable, sealed policy |
10
+ | Guardrails | What may never be broken here? | Stable, sealed project policy |
11
+ | Knowledge | What do we know, and why? | Reviewed until stale/deprecated/invalidated |
12
+ | Backlog | What is provisioned but not started? | Tasks with `status: backlog` |
9
13
  | Feature | Why does this initiative matter? | Long-lived |
10
- | Task | What atomic outcome is approved? | Until outcome/closure |
11
- | Sprint | When are related Tasks grouped? | Timebox/batch |
12
- | Run | How did one execution attempt happen? | Immutable attempt history |
13
- | Memory | What do we know, and why? | Reviewed until stale/deprecated/invalidated |
14
+ | Sprint | Which Tasks ship together? | Feature, fix, or maintenance batch |
15
+ | Task | What concrete outcome must be delivered? | Until outcome/closure |
16
+ | Run | What happened while executing a Task or Sprint? | Optional audit/handoff record |
14
17
 
15
18
  ```text
16
- FEAT-003
19
+ SPRINT-012 (type: fix)
17
20
  └── TASK-018
18
- ├── executed_byRUN-044
19
- ├── included_inSPRINT-012
20
- ├── constrained_byDEC-018
21
- └── generatedINS-041
21
+ ├── featureFEAT-003
22
+ ├── depends_onTASK-014, DEC-018
23
+ ├── guardrailsGR-004
24
+ └── runRUN-044 (optional)
22
25
  ```
23
26
 
24
- Task is always the executable unit. A Task may be independent of a Sprint. Sprint never substitutes for Task. A retry creates another Run for the same Task.
27
+ Task is the executable unit. A Task may be independent of a Sprint. A Sprint groups Tasks and may be `feature`, `fix`, or `maintenance`. Runs are optional and never substitute for a Task's direct Markdown handoff.
25
28
 
26
29
  ## Canonical artifacts
27
30
 
28
- All artifacts carry `id`, `kind`, `status`, `created`, `updated`, and `method`. Relations live in frontmatter for structural ownership and in `## Relations` for extensible graph edges. The generated [`SCHEMA.md`](SCHEMA.md) is the authoritative inventory.
31
+ All artifacts carry `id`, `kind`, `status`, `created`, `updated`, and `method`. Relations use simple frontmatter and relative links: `sprint: SPRINT-012`, `feature: FEAT-003`, `depends_on: [TASK-014, DEC-018]`, and `## Related`. Unknown fields and sections are preserved. The generated [`SCHEMA.md`](SCHEMA.md) is the authoritative inventory.
29
32
 
30
33
  ## Operational flow
31
34
 
32
- Approval creates one Task and one Run. The Run progresses `executing validating learning completed|failed|blocked`, while the Task mirrors `runningvalidatinglearningcompleted|failed|blocked`. Pair mutations are recoverable.
35
+ Approval creates or refines a Task. An optional Run can record strict audit or handoff history, but no Run, ledger, permit, or status synchronization blocks normal Markdown work. An approved Task continues through discover implementverifyfix verify until its `## Done when` contract is delivered.
33
36
 
34
- Feature and Sprint provide context/grouping and do not own execution history. Review attaches evidence. Memory explains decisions and constraints across all of them.
37
+ Feature and Sprint provide context/grouping and do not own execution history. Review attaches evidence. Knowledge, Decisions, and Insights explain constraints across all of them. Core and Guardrails are sealed Markdown policy: only explicit owner-reviewed maintenance may change them.
35
38
 
36
39
  ## Generated projections
37
40
 
@@ -1,18 +1,19 @@
1
1
  # Quickstart
2
2
 
3
- Get from "never heard of it" to your first approved Run in under 10 minutes.
3
+ Get from "never heard of it" to your first delivered Task in under 10 minutes.
4
4
  No `SPEC.md` reading required.
5
5
 
6
6
  ## The three-minute mental model
7
7
 
8
8
  ScrumRun gives an AI coding agent a small vocabulary and a project memory.
9
9
 
10
- - **Task** — one atomic piece of work.
11
- - **Sprint** — a batch of Tasks grouped by time or theme. Optional.
12
- - **Run** — one attempt at executing a Task. Retries create new Runs; the
13
- previous one is never overwritten.
14
- - **Feature** — a bigger initiative that groups Tasks and its own decisions.
15
- - **Memory** — what the project learned: facts, decisions, insights, dossiers.
10
+ - **Core** — how the agent works; read first and never edited during product work.
11
+ - **Guardrails** — rules that cannot be broken.
12
+ - **Knowledge** — facts, decisions, insights, and dossiers about the project.
13
+ - **Task** — one concrete delivery, independent or inside a Sprint.
14
+ - **Sprint** — a feature, fix, or maintenance batch of Tasks. Optional.
15
+ - **Feature** — a bigger initiative that groups delivery context.
16
+ - **Run** — optional audit/handoff Markdown for a Task or Sprint.
16
17
 
17
18
  Everything lives as Markdown under `.scrumrun/`. Any Markdown-capable agent
18
19
  can follow it.
@@ -64,24 +65,25 @@ command (`| less`, `> intake.txt`) or set `NO_COLOR=1` to get the plain
64
65
  Markdown summary instead; add `--json` for a fully structured payload
65
66
  you can feed to CI or a downstream tool.
66
67
 
67
- Only then does a Task and a Run get created.
68
+ Only then does the Task become approved. The agent executes it directly in code and Markdown; a Run is optional.
68
69
 
69
- ## Watching the Run
70
+ ## Delivering the Task
70
71
 
71
- The agent executes inside the approved scope. Every step lands in an
72
- append-only ledger under `.scrumrun/runs/RUN-NNN.md` with a stable event
73
- id, timestamp, actor, reason, and typed evidence.
72
+ The agent executes inside the approved scope until `## Done when` is true.
73
+ It does not stop after an inventory, partial fix, or progress report. Any
74
+ missing implementation discovered in scope is work to do now, not a follow-up.
74
75
 
75
76
  ```
76
- RUN-001-EVT-001 planned by owner reason: "checkout double-charge fix"
77
- RUN-001-EVT-002 executed command: npm test → 132 passed
78
- RUN-001-EVT-003 validated (REV-001) guardrail checks: passed
79
- RUN-001-EVT-004 learned (INS-001) "refresh triggers duplicate submit"
80
- RUN-001-EVT-005 completed
77
+ TASK-001
78
+ inspect the duplicate-submit path
79
+ implement the fix
80
+ run the relevant checks
81
+ → correct failures
82
+ → write ## Completion and status: completed
81
83
  ```
82
84
 
83
- A retry does not overwrite `RUN-001`. It creates `RUN-002` beside it. The
84
- old attempt stays as evidence.
85
+ A Run may be added when a strict audit or detailed handoff is useful. It never
86
+ needs to exist for normal work to start or finish.
85
87
 
86
88
  You can render a Run's ledger as a human timeline instead of reading the
87
89
  raw JSON:
package/docs/SCHEMA.md CHANGED
@@ -20,9 +20,9 @@ The boundaries above are deliberately different: SPEC owns meanings, the executa
20
20
  | Kind | Stable ID | Canonical directory | Allowed initial status | Truth owned by this artifact |
21
21
  |---|---|---|---|---|
22
22
  | feature | `FEAT-NNN` | `features/` | `backlog`, `proposed` | initiative purpose, scope, dependencies, and lifecycle |
23
- | task | `TASK-NNN` | `tasks/` | `backlog`, `proposed`, `running` | scope, acceptance criteria, approval, and intended status |
24
- | sprint | `SPRINT-NNN` | `sprints/` | `proposed` | timebox or delivery-batch membership; never execution history |
25
- | run | `RUN-NNN` | `runs/` | `executing` | append-only execution events, evidence, result, and attempt number |
23
+ | task | `TASK-NNN` | `tasks/` | `backlog`, `proposed`, `in_progress`, `running` | scope, owner-defined sections, links, and status |
24
+ | sprint | `SPRINT-NNN` | `sprints/` | `proposed` | timebox or delivery-batch membership; may be feature, fix, or maintenance |
25
+ | run | `RUN-NNN` | `runs/` | `executing` | optional human-readable execution record and outcome |
26
26
  | review | `REV-NNN` | `reviews/` | `proposed` | scoped findings, checks, evidence, and verdict |
27
27
  | knowledge | `K-NNN` | `memory/knowledge/` | `candidate` | approved evidence-backed fact and validity |
28
28
  | decision | `DEC-NNN` | `memory/decisions/` | `open` | decision, rationale, validity, and lifecycle |
@@ -37,9 +37,9 @@ Every artifact also requires `id`, `kind`, `status`, `created`, `updated`, and `
37
37
  |---|---|---|---|
38
38
  | `feature` | feature (`FEAT-NNN`) | 0..1 | long-lived initiative containing the artifact |
39
39
  | `sprint` | sprint (`SPRINT-NNN`) | 0..1 | optional delivery batch containing a Task or Run |
40
- | `task` | task (`TASK-NNN`) | 1 for Run; otherwise 0..1 | atomic work executed or reviewed by the artifact |
40
+ | `task` | task (`TASK-NNN`) | 0..1 | atomic work executed or reviewed by the artifact |
41
41
 
42
- Task is the atomic unit. A Task may have zero or one Sprint. A Task may have many Runs, but every Run belongs to exactly one Task and has a monotonically increasing attempt number within that Task. Sprint membership is authoritative on `Task.sprint`; a Sprint's `## Tasks` list is a human-readable projection that must agree with it.
42
+ Task is the atomic unit. A Task may have zero or one Sprint. A Run is optional Markdown history and may reference either a Task or a Sprint; it never controls Task status in Markdown-first work. Sprint membership is authoritative on `Task.sprint`; a Sprint's `## Tasks` list is a human-readable projection that must agree with it. Additional owner-defined relations such as `depends_on: [TASK-014, DEC-018]` are preserved as local Markdown graph data.
43
43
 
44
44
  ## Scalar constraints
45
45
 
@@ -58,14 +58,14 @@ Newly authored Runs use `ledger: 1`. Their `## Events` section contains append-o
58
58
 
59
59
  Every event requires `schema`, `id`, contiguous `sequence`, RFC3339 `occurred_at`, `timestamp_precision`, `actor`, `from`, `to`, `reason`, and structured `evidence`. Event types are `transition`, `snapshot`, `guardrail`, `mutation`. Evidence kinds are `approval`, `command`, `test`, `file`, `review`, `decision`, `insight`, `risk`, `note`, `migration`, `legacy`, `guardrail`, `mutation`.
60
60
 
61
- A native ledger begins with `created → executing`; an evidenced migration `snapshot` may establish one historical baseline without inventing missing transitions. Event order, transition legality, final status, updated date, and completion evidence are machine-validated. Run owns the event history; Task stores its intended scope and synchronized current status without copying Run events.
61
+ A native ledger begins with `created → executing`; an evidenced migration `snapshot` may establish one historical baseline without inventing missing transitions. Event order, transition legality, final status, updated date, and completion evidence are machine-validated when a strict audit Run is used. Run owns optional event history; Task Markdown owns the delivered scope and status in normal work.
62
62
 
63
63
  ## Truth questions
64
64
 
65
65
  - **feature:** Why does this initiative exist?
66
- - **task:** What approved atomic outcome is intended?
67
- - **sprint:** When are related Tasks grouped?
68
- - **run:** How did one execution attempt actually happen?
66
+ - **task:** What concrete outcome is intended?
67
+ - **sprint:** Which Tasks are grouped for this delivery?
68
+ - **run:** What happened while executing a Task or Sprint?
69
69
  - **review:** What independent validation was performed?
70
70
  - **knowledge:** What verified project fact is reusable?
71
71
  - **decision:** What normative choice constrains future work?
@@ -77,7 +77,7 @@ A native ledger begins with `created → executing`; an evidenced migration `sna
77
77
  | Kind | Declared transitions |
78
78
  |---|---|
79
79
  | feature | `backlog` → `proposed`, `active`, `cancelled`<br>`proposed` → `active`, `cancelled`<br>`active` → `paused`, `completed`, `cancelled`<br>`completed` → terminal<br>`paused` → `active`, `cancelled`<br>`cancelled` → terminal |
80
- | task | `backlog` → `proposed`, `running`, `cancelled`<br>`proposed` → `running`, `cancelled`<br>`running` → `validating`, `failed`, `blocked`, `cancelled`<br>`validating` → `learning`, `failed`, `blocked`<br>`learning` → `completed`, `failed`, `blocked`<br>`partial` → `running`, `cancelled`<br>`completed` → terminal<br>`failed` → `running`, `cancelled`<br>`blocked` → `running`, `cancelled`<br>`cancelled` → terminal |
80
+ | task | `backlog` → `proposed`, `in_progress`, `running`, `cancelled`<br>`proposed` → `in_progress`, `running`, `cancelled`<br>`in_progress` → `completed`, `failed`, `blocked`, `cancelled`<br>`running` → `validating`, `completed`, `failed`, `blocked`, `cancelled`<br>`validating` → `learning`, `completed`, `failed`, `blocked`<br>`learning` → `completed`, `failed`, `blocked`<br>`partial` → `in_progress`, `running`, `cancelled`<br>`completed` → terminal<br>`failed` → `in_progress`, `running`, `cancelled`<br>`blocked` → `in_progress`, `running`, `cancelled`<br>`cancelled` → terminal |
81
81
  | sprint | `proposed` → `running`, `cancelled`<br>`running` → `partial`, `completed`, `blocked`, `cancelled`<br>`partial` → `running`, `completed`, `cancelled`<br>`completed` → terminal<br>`blocked` → `running`, `cancelled`<br>`cancelled` → terminal |
82
82
  | run | `executing` → `validating`, `failed`, `blocked`<br>`validating` → `learning`, `failed`, `blocked`<br>`learning` → `completed`, `failed`, `blocked`<br>`partial` → `executing`, `failed`, `blocked`<br>`completed` → terminal<br>`failed` → terminal<br>`blocked` → `executing`, `failed` |
83
83
  | review | `proposed` → `running`<br>`running` → `passed`, `failed`<br>`passed` → `archived`<br>`failed` → `running`, `archived`<br>`archived` → terminal |
@@ -65,7 +65,7 @@ const nouns = Object.freeze({
65
65
  subjects: {
66
66
  project: ["--show", "--language", "--interaction", "--approval", "--quick-tasks"],
67
67
  init: ["--local", "--shared", "--lean", "--no-agent-hint", "--force"],
68
- update: ["all [--migrate]", "codex [--migrate]", "opencode [--migrate]", "claude [--migrate]"],
68
+ update: ["all [--project] [--seal-policy] [--migrate]", "codex [--project] [--seal-policy] [--migrate]", "opencode [--project] [--seal-policy] [--migrate]", "claude [--project] [--seal-policy] [--migrate]"],
69
69
  migrate: ["--to 2 --dry-run", "--to 2 --apply", "--to 2 --rollback"],
70
70
  doctor: ["all [--strict] [--recover] [--dry-run]", "codex [--strict] [--recover] [--dry-run]", "opencode [--strict] [--recover] [--dry-run]", "claude [--strict] [--recover] [--dry-run]"],
71
71
  uninstall: ["--force"],
@@ -29,15 +29,16 @@ ${grammarLines().join("\n")}
29
29
 
30
30
  - Natural-language product work begins with a read-only understanding pass; do not invoke \`plan intake\` merely to satisfy procedure.
31
31
  - Intake, contextualization, policy, risk, classification, and planning are read-only until explicit approval.
32
- - After approval, work directly in source files and relevant \`.scrumrun/\` Markdown. Create/refine a Task, acceptance criteria, technical summary, and follow-ups directly. Feature/Sprint/Run are useful only when they add context.
32
+ - After approval, work directly in source files and relevant \`.scrumrun/\` Markdown until the approved Task is delivered. Keep executing discover → implement → verify → fix → verify; a progress report is allowed only when the owner asks for it and never ends the workflow. Do not answer with an inventory, partial progress report, decomposition, or remaining-work list; those are internal steps. A gap discovered in scope is work to implement now, not a “next step”. Feature/Sprint/Run are useful only when they add context.
33
33
  - A Run is optional audit/handoff context, never a prerequisite for starting, amending, or completing a Task. Do not block on a missing Run, a legacy status, or stale generated state.
34
34
  - The CLI can inspect/repair/report structured artifacts, but it does not own the daily workflow.
35
35
  - \`guardrails.md\` is canonical project policy; \`golden-rules.md\` is v1 compatibility only.
36
36
  - Evaluate active Guardrails as \`passed\`, \`blocked\`, or \`deferred\`; cite exact \`GR-NNN\` ids and keep deferred execution gates visible.
37
- - Block only for an explicit Guardrail, secret/security risk, destructive action without approval, or an unmet required Acceptance Criterion. Optional unrun E2E/review coverage is a follow-up/risk, not a failed Run.
37
+ - Block only for an explicit Guardrail, secret/security risk, destructive action without approval, or an unmet required delivery criterion. \`Follow-ups\` may only contain work outside the approved \`Done when\` contract; optional unrun E2E/review coverage is a follow-up/risk, not a failed Run.
38
38
  - Use the CLI only for \`init\`, \`update --project\`, \`migrate\`, \`repair\`, \`doctor\`, reports, or release checks. Do not invoke \`npx scrumrun@latest\` during execution.
39
39
  - Never invoke \`plan run --fail|--block|--retry|--finalize|--complete|--validate\` or \`plan task --start\` during normal work. These optional strict-audit commands must not decide a Task outcome.
40
40
  - Strict per-path Mutation Gateway permits and ledger finalization remain available only when the owner explicitly requests strict execution.
41
+ - Never edit \`core.md\` or \`guardrails.md\` during product work. They are sealed policy; owner-requested policy changes are reviewed and sealed at the maintenance edge.
41
42
  - Knowledge/Decision/Insight records require evidence; AI-proposed Insights remain \`candidate\` until confirmed.
42
43
  - Never print vault values or write before approval.
43
44
  - Unknown nouns, subjects, actions, ids, or ambiguous approval must produce a deterministic explanation, never a guessed mutation.
@@ -29,6 +29,31 @@ function generateBriefing(scrumDir, repository) {
29
29
  }))
30
30
  .slice(0, 5);
31
31
 
32
+ // Blocked-by-dependency: Tasks with `depends_on: [ID, ...]` in frontmatter
33
+ // where at least one target artifact is missing or not terminal. This is a
34
+ // visibility signal, not a hard gate — the agent reads it and decides.
35
+ const allById = new Map();
36
+ for (const kind of Object.keys(snapshot.records)) {
37
+ for (const r of snapshot.records[kind] || []) {
38
+ if (r.id) allById.set(r.id, r);
39
+ }
40
+ }
41
+ const blockedLines = [];
42
+ for (const task of snapshot.records.task || []) {
43
+ if (!task.id || TERMINAL.has(task.status)) continue;
44
+ const deps = Array.isArray(task.depends_on) ? task.depends_on : [];
45
+ const blocking = [];
46
+ for (const depId of deps) {
47
+ if (typeof depId !== "string") continue;
48
+ const dep = allById.get(depId);
49
+ if (!dep) blocking.push(`${depId} (missing)`);
50
+ else if (!TERMINAL.has(dep.status)) blocking.push(`${depId} (${dep.status})`);
51
+ }
52
+ if (blocking.length) {
53
+ blockedLines.push(`- ${task.id} waits on ${blocking.join(", ")} — ${task.title || task.id}`);
54
+ }
55
+ }
56
+
32
57
  const completedRuns = (snapshot.records.run || [])
33
58
  .filter((r) => r.status === "completed")
34
59
  .slice(-5)
@@ -76,6 +101,10 @@ Progressive disclosure: read this first; go deeper only if the briefing lacks wh
76
101
 
77
102
  ${activeWork.length ? activeWork.join("\n") : "- No active canonical work."}
78
103
 
104
+ ## Blocked by dependency
105
+
106
+ ${blockedLines.length ? blockedLines.join("\n") : "- None. All active Tasks have their `depends_on` targets terminal (or none declared)."}
107
+
79
108
  ## Recent
80
109
 
81
110
  ${recentLines.length ? recentLines.join("\n") : "- No completed Runs."}
@@ -57,7 +57,7 @@ function sprintBody(title, request, created, taskId) {
57
57
  function buildTaskBody(request, classification, approvalId, fingerprint, risk, previewSection, links = {}) {
58
58
  const featureSection = links.feature ? `\n## Feature\n\n- ${links.feature}\n` : "";
59
59
  const sprintSection = links.sprint ? `\n## Sprint\n\n- ${links.sprint}\n` : "";
60
- return `# ${titleFor(request)}\n\n## Request\n\n${request}\n\n## Acceptance Criteria\n\n- [ ] _Define what "done" means before execution._\n\n## Validation Scope\n\n- Required: validate the stated Acceptance Criteria and active Guardrails proportionately to risk.\n- Non-blocking: tests, reviews, or environments not explicitly required by the owner, Acceptance Criteria, or an active Guardrail. Record a material coverage gap as a follow-up; do not fail the Task solely because that optional check was not run.\n${previewSection}${featureSection}${sprintSection}\n## Classification\n\n- Type: ${classification.type}\n- Reason: ${classification.reason}\n- Risk: ${risk.level}\n\n## Approval\n\n- Explicit approval token: ${approvalId}\n- Context fingerprint: ${fingerprint}`;
60
+ return `# ${titleFor(request)}\n\n## Request\n\n${request}\n\n## Done when\n\n- [ ] _State the smallest observable delivery contract before execution._\n\n## Validation Scope\n\n- Required: validate the stated Done when contract and active Guardrails proportionately to risk.\n- Non-blocking: tests, reviews, or environments not explicitly required by the owner, Done when contract, or an active Guardrail. Record a material coverage gap as a follow-up only when it is outside the approved contract; do not fail the Task solely because that optional check was not run.\n\n## Completion\n\n- _Fill this once, after the delivery contract is satisfied._\n${previewSection}${featureSection}${sprintSection}\n## Classification\n\n- Type: ${classification.type}\n- Reason: ${classification.reason}\n- Risk: ${risk.level}\n\n## Approval\n\n- Explicit approval token: ${approvalId}\n- Context fingerprint: ${fingerprint}`;
61
61
  }
62
62
 
63
63
  function stateFingerprint(repository) {
@@ -595,9 +595,9 @@ function planArtifactBody(kind, title, created) {
595
595
  "",
596
596
  title,
597
597
  "",
598
- "## Acceptance Criteria",
598
+ "## Done when",
599
599
  "",
600
- '- [ ] _Define what "done" means before execution._',
600
+ "- [ ] _State the smallest observable delivery contract before execution._",
601
601
  "",
602
602
  "## Source",
603
603
  "",
@@ -792,7 +792,7 @@ function amendPlanArtifact(projectRoot, kind, id, options = {}) {
792
792
  let body = artifact.body;
793
793
  if (options.title !== undefined) body = replaceTitle(body, options.title);
794
794
  if (options.request !== undefined) body = replaceSection(body, "Request", options.request);
795
- if (options.acceptance !== undefined) body = replaceSection(body, "Acceptance Criteria", options.acceptance.map((item) => `- [ ] ${normalizeAmendText(item, "Acceptance criterion")}`).join("\n"));
795
+ if (options.acceptance !== undefined) body = replaceFirstKnownSection(body, ["Done when", "Acceptance Criteria"], options.acceptance.map((item) => `- [ ] ${normalizeAmendText(item, "Delivery criterion")}`).join("\n"));
796
796
  if (options.purpose !== undefined) body = replaceFirstKnownSection(body, ["Purpose", "Motivation"], options.purpose);
797
797
  if (options.exitCriteria !== undefined) body = replaceFirstKnownSection(body, ["Exit Criteria", "Exit criteria"], options.exitCriteria.map((item) => `- [ ] ${normalizeAmendText(item, "Exit criterion")}`).join("\n"));
798
798
  if (options.timebox !== undefined) body = replaceSection(body, "Timebox", options.timebox);
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+
3
+ // Daily work is intentionally Markdown-first. This module keeps the
4
+ // enforcement at the boundary: project policy is pinned when ScrumRun is
5
+ // initialized/updated and `doctor --strict` / release audits detect drift.
6
+
7
+ const crypto = require("node:crypto");
8
+ const fs = require("node:fs");
9
+ const path = require("node:path");
10
+
11
+ function sha256(value) {
12
+ return crypto.createHash("sha256").update(value).digest("hex");
13
+ }
14
+
15
+ function readRegular(file) {
16
+ if (!fs.existsSync(file) || !fs.lstatSync(file).isFile() || fs.lstatSync(file).isSymbolicLink()) return null;
17
+ return fs.readFileSync(file, "utf8");
18
+ }
19
+
20
+ function expectedCoreFingerprint(packageRoot = path.resolve(__dirname, "../..")) {
21
+ const core = readRegular(path.join(packageRoot, "CORE.md"));
22
+ return core === null ? null : sha256(core);
23
+ }
24
+
25
+ function readPolicyIntegrity(scrumDir) {
26
+ const marker = path.join(scrumDir, "method.json");
27
+ const raw = readRegular(marker);
28
+ if (raw === null) return { marker: null, integrity: null, error: "method.json is missing or unsafe" };
29
+ try {
30
+ const parsed = JSON.parse(raw);
31
+ return { marker: parsed, integrity: parsed.integrity || null, error: null };
32
+ } catch (error) {
33
+ return { marker: null, integrity: null, error: error.message };
34
+ }
35
+ }
36
+
37
+ function sealPolicyIntegrity(scrumDir, { includeGuardrails = false, coreFingerprint = expectedCoreFingerprint() } = {}) {
38
+ const state = readPolicyIntegrity(scrumDir);
39
+ if (state.error) throw new Error(`Cannot seal ScrumRun policy: ${state.error}`);
40
+ const core = readRegular(path.join(scrumDir, "core.md"));
41
+ if (core === null) throw new Error("Cannot seal ScrumRun policy: core.md is missing or unsafe.");
42
+ const guardrails = readRegular(path.join(scrumDir, "guardrails.md"));
43
+ if (guardrails === null) throw new Error("Cannot seal ScrumRun policy: guardrails.md is missing or unsafe.");
44
+ const next = {
45
+ ...state.marker,
46
+ workflow: { ...(state.marker.workflow || {}), daily: "markdown-first" },
47
+ integrity: {
48
+ ...(state.integrity || {}),
49
+ schema: 1,
50
+ core_sha256: sha256(core),
51
+ core_package_sha256: coreFingerprint || sha256(core),
52
+ ...(includeGuardrails || !state.integrity || !state.integrity.guardrails_sha256
53
+ ? { guardrails_sha256: sha256(guardrails) }
54
+ : {})
55
+ }
56
+ };
57
+ return `${JSON.stringify(next, null, 2)}\n`;
58
+ }
59
+
60
+ function auditPolicyIntegrity(scrumDir, { coreFingerprint = expectedCoreFingerprint() } = {}) {
61
+ const state = readPolicyIntegrity(scrumDir);
62
+ if (state.error) return [{ severity: "critical", code: "POLICY_MARKER", message: state.error }];
63
+ const integrity = state.integrity;
64
+ if (!integrity || integrity.schema !== 1) {
65
+ return [{ severity: "warning", code: "POLICY_INTEGRITY_UNSEALED", message: "Policy fingerprints are not sealed. Run `scrumrun update --project --seal-policy` after owner review." }];
66
+ }
67
+ const findings = [];
68
+ const core = readRegular(path.join(scrumDir, "core.md"));
69
+ const guardrails = readRegular(path.join(scrumDir, "guardrails.md"));
70
+ if (core === null) findings.push({ severity: "critical", code: "CORE_UNSAFE", message: "core.md is missing or unsafe." });
71
+ else {
72
+ const actual = sha256(core);
73
+ if (actual !== integrity.core_sha256) findings.push({ severity: "high", code: "CORE_TAMPERED", message: "core.md differs from the owner-sealed policy. Restore it with `scrumrun update --project`." });
74
+ if (coreFingerprint && actual !== coreFingerprint) findings.push({ severity: "high", code: "CORE_PACKAGE_DRIFT", message: "core.md differs from the installed ScrumRun Core. Review then run `scrumrun update --project`." });
75
+ }
76
+ if (guardrails === null) findings.push({ severity: "critical", code: "GUARDRAILS_UNSAFE", message: "guardrails.md is missing or unsafe." });
77
+ else if (sha256(guardrails) !== integrity.guardrails_sha256) {
78
+ findings.push({ severity: "high", code: "GUARDRAILS_TAMPERED", message: "guardrails.md changed after owner sealing. Review it, then explicitly run `scrumrun update --project --seal-policy`." });
79
+ }
80
+ return findings;
81
+ }
82
+
83
+ module.exports = { auditPolicyIntegrity, expectedCoreFingerprint, sealPolicyIntegrity, sha256 };
@@ -17,6 +17,7 @@ function sha256(content) {
17
17
 
18
18
  function scalar(value) {
19
19
  if (value === null || value === undefined) return "null";
20
+ if (Array.isArray(value)) return `[${value.map((item) => scalar(item)).join(", ")}]`;
20
21
  if (typeof value === "boolean" || typeof value === "number") return String(value);
21
22
  const text = String(value);
22
23
  if (/^[A-Za-z0-9._/-]+$/.test(text)) return text;
@@ -36,6 +37,11 @@ function parseScalar(value) {
36
37
  return text;
37
38
  }
38
39
  }
40
+ if (text.startsWith("[") && text.endsWith("]")) {
41
+ const inner = text.slice(1, -1).trim();
42
+ if (!inner) return [];
43
+ return inner.split(",").map((item) => parseScalar(item));
44
+ }
39
45
  return text;
40
46
  }
41
47
 
@@ -102,6 +108,9 @@ function validateArtifact(record, expectedKind = null) {
102
108
  errors.push(`${record.kind}.${field} must reference ${target.prefix}-NNN`);
103
109
  }
104
110
  }
111
+ if (record.kind === "run" && (record.task === undefined || record.task === null) && (record.sprint === undefined || record.sprint === null)) {
112
+ errors.push("run must reference TASK-NNN or SPRINT-NNN");
113
+ }
105
114
  for (const [field, constraint] of Object.entries(SCALAR_FIELDS)) {
106
115
  if (!constraint.kinds.includes(record.kind)) continue;
107
116
  if (constraint.required && (record[field] === undefined || record[field] === null)) {
@@ -14,6 +14,7 @@ const { pendingTransactionStatus } = require("./transaction");
14
14
  const { configWeakeningAttempts, validateGuardrailDocument } = require("../runtime/policy-engine");
15
15
  const { auditActiveWorkspace } = require("../runtime/mutation-gateway");
16
16
  const { canonicalPaths, PATHS_SCHEMA_VERSION } = require("./paths");
17
+ const { auditPolicyIntegrity } = require("../runtime/policy-integrity");
17
18
 
18
19
  const INVARIANTS = Object.freeze([
19
20
  { id: "I-01", summary: "pre-approval work is read-only", tests: ["intake builds bounded context without writing"] },
@@ -79,10 +80,10 @@ function auditProject(projectRoot) {
79
80
  if (methodMarker.method !== METHOD_VERSION) findings.push(finding("critical", "METHOD_VERSION", `method.json must declare ${METHOD_VERSION}.`, marker));
80
81
  const expectedPaths = canonicalPaths();
81
82
  if (!methodMarker.paths || typeof methodMarker.paths !== "object" || Array.isArray(methodMarker.paths)) {
82
- findings.push(finding("high", "METHOD_PATHS_MISSING", `method.json must declare a canonical "paths" block so agents navigate by declaration, not by search. Run \`scrumrun update --migrate\` to backfill.`, marker));
83
+ findings.push(finding("warning", "METHOD_PATHS_MISSING", `method.json is missing a canonical "paths" block. Non-blocking in Markdown-first daily work; run \`scrumrun update --migrate\` if you want the declared index.`, marker));
83
84
  } else {
84
85
  const drift = diffPathIndex(expectedPaths, methodMarker.paths);
85
- for (const entry of drift) findings.push(finding("high", "METHOD_PATHS_DRIFT", `method.json paths[${entry.label}] is ${entry.actual === undefined ? "missing" : `"${entry.actual}"`}; expected "${entry.expected}". Regenerate via \`update --migrate\`.`, marker));
86
+ for (const entry of drift) findings.push(finding("warning", "METHOD_PATHS_DRIFT", `method.json paths[${entry.label}] is ${entry.actual === undefined ? "missing" : `"${entry.actual}"`}; expected "${entry.expected}". Non-blocking; regenerate via \`update --migrate\` when convenient.`, marker));
86
87
  if (methodMarker.paths_schema !== PATHS_SCHEMA_VERSION) {
87
88
  findings.push(finding("warning", "METHOD_PATHS_SCHEMA", `method.json paths_schema is ${methodMarker.paths_schema || "missing"}; expected ${PATHS_SCHEMA_VERSION}.`, marker));
88
89
  }
@@ -94,6 +95,7 @@ function auditProject(projectRoot) {
94
95
  const file = path.join(scrumDir, relative);
95
96
  if (!fs.existsSync(file) || !fs.lstatSync(file).isFile()) findings.push(finding("high", "CANONICAL_MISSING", `${relative} is missing or unsafe.`, file));
96
97
  }
98
+ for (const item of auditPolicyIntegrity(scrumDir)) findings.push(finding(item.severity, item.code, item.message, marker));
97
99
  const guardrailsFile = path.join(scrumDir, "guardrails.md");
98
100
  const guardrails = fs.existsSync(guardrailsFile) && fs.lstatSync(guardrailsFile).isFile() ? fs.readFileSync(guardrailsFile, "utf8") : "";
99
101
  const guardrailValidation = validateGuardrailDocument(guardrails);
@@ -141,9 +143,9 @@ function auditProject(projectRoot) {
141
143
  task = null;
142
144
  }
143
145
  }
144
- if (run.record && !run.record.task) {
145
- findings.push(finding("high", "RUN_TASK_MISSING", `${run.record.id} has no task reference (record.task is null).`, run.file));
146
- } else if (run.record && (!task || task.errors.length)) {
146
+ if (run.record && !run.record.task && !run.record.sprint) {
147
+ findings.push(finding("high", "RUN_TARGET_MISSING", `${run.record.id} must reference a Task or Sprint.`, run.file));
148
+ } else if (run.record && run.record.task && (!task || task.errors.length)) {
147
149
  findings.push(finding("high", "RUN_TASK_MISSING", `${run.record.id} references missing or invalid ${run.record.task}.`, run.file));
148
150
  }
149
151
  if (run.record && task && !task.errors.length && (run.record.sprint || null) !== (task.record.sprint || null)) {
@@ -170,6 +172,7 @@ function auditProject(projectRoot) {
170
172
  }
171
173
  }
172
174
  const byId = new Map(Object.values(records).flat().filter((artifact) => artifact.record).map((artifact) => [artifact.record.id, artifact]));
175
+ const markdownFirst = methodMarker && methodMarker.workflow && methodMarker.workflow.daily === "markdown-first";
173
176
  for (const task of records.task || []) {
174
177
  for (const [field, prefix] of [["feature", "FEAT"], ["sprint", "SPRINT"]]) {
175
178
  const target = task.record && task.record[field];
@@ -182,7 +185,7 @@ function auditProject(projectRoot) {
182
185
  }
183
186
  const attemptsByTask = new Map();
184
187
  for (const run of records.run || []) {
185
- if (!run.record || run.errors.length) continue;
188
+ if (!run.record || run.errors.length || !run.record.task) continue;
186
189
  if (!attemptsByTask.has(run.record.task)) attemptsByTask.set(run.record.task, []);
187
190
  attemptsByTask.get(run.record.task).push(run.record.attempt);
188
191
  }
@@ -199,11 +202,14 @@ function auditProject(projectRoot) {
199
202
  .filter((run) => run.record && !run.errors.length && run.record.task === task.record.id)
200
203
  .sort((left, right) => right.record.attempt - left.record.attempt);
201
204
  if (!attempts.length) {
205
+ if (markdownFirst) continue;
202
206
  if (["running", "validating", "learning", "partial"].includes(task.record.status)) {
203
207
  findings.push(finding(
204
- "high",
208
+ markdownFirst ? "warning" : "high",
205
209
  "TASK_ORPHANED",
206
- `${task.record.id}.status is ${task.record.status}, but no canonical Run references it. Review with \`scrumrun repair --recover-orphan-tasks\`, then apply the explicit recovery and start the Task to create its first Run.`,
210
+ markdownFirst
211
+ ? `${task.record.id}.status is ${task.record.status} without a Run. This is valid Markdown-first work; keep the Task handoff current.`
212
+ : `${task.record.id}.status is ${task.record.status}, but no canonical Run references it. Review with \`scrumrun repair --recover-orphan-tasks\`, then apply the explicit recovery and start the Task to create its first Run.`,
207
213
  task.file
208
214
  ));
209
215
  }
@@ -219,17 +225,13 @@ function auditProject(projectRoot) {
219
225
  blocked: "blocked",
220
226
  partial: "partial"
221
227
  };
222
- if (taskStatuses[latest.status] && task.record.status !== taskStatuses[latest.status]) {
228
+ if (!markdownFirst && taskStatuses[latest.status] && task.record.status !== taskStatuses[latest.status]) {
223
229
  findings.push(finding("high", "TASK_RUN_STATUS_MISMATCH", `${task.record.id}.status ${task.record.status} disagrees with latest ${latest.id}.status ${latest.status}.`, task.file));
224
230
  }
225
231
  }
226
- for (const task of records.task || []) {
227
- if (!task.record || task.errors.length) continue;
228
- if (["backlog", "proposed", "cancelled"].includes(task.record.status)) continue;
229
- if (!/^## Acceptance Criteria\b/m.test(task.body || "")) {
230
- findings.push(finding("warning", "ACCEPTANCE_CRITERIA_MISSING", `${task.record.id} has no Acceptance Criteria section; define what "done" means before execution.`, task.file));
231
- }
232
- }
232
+ // Task bodies are intentionally extensible Markdown. Project Guardrails may
233
+ // require sections for selected Tasks; the kernel never requires one global
234
+ // heading or rejects unknown owner-defined structure.
233
235
  for (const sprint of records.sprint || []) {
234
236
  if (!sprint.record || sprint.errors.length) continue;
235
237
  const heading = /^## Tasks[ \t]*$/m.exec(sprint.body);
package/lib/v2/paths.js CHANGED
@@ -56,10 +56,11 @@ function flattenPaths(paths = CANONICAL_PATHS, prefix = "") {
56
56
  return out;
57
57
  }
58
58
 
59
- function renderMethodJson({ methodVersion, layout = "v2", schemas = {}, migratedFrom, migration } = {}) {
59
+ function renderMethodJson({ methodVersion, layout = "v2", schemas = {}, workflow = { daily: "markdown-first" }, migratedFrom, migration } = {}) {
60
60
  const payload = {
61
61
  method: methodVersion,
62
62
  layout,
63
+ workflow,
63
64
  paths_schema: PATHS_SCHEMA_VERSION,
64
65
  paths: canonicalPaths(),
65
66
  schemas
package/lib/v2/schema.js CHANGED
@@ -38,8 +38,8 @@ const ARTIFACT_TYPES = deepFreeze({
38
38
  task: {
39
39
  prefix: "TASK",
40
40
  directory: "tasks",
41
- initial: ["backlog", "proposed", "running"],
42
- statuses: ["backlog", "proposed", "running", "validating", "learning", "partial", "completed", "failed", "blocked", "cancelled"]
41
+ initial: ["backlog", "proposed", "in_progress", "running"],
42
+ statuses: ["backlog", "proposed", "in_progress", "running", "validating", "learning", "partial", "completed", "failed", "blocked", "cancelled"]
43
43
  },
44
44
  sprint: {
45
45
  prefix: "SPRINT",
@@ -90,7 +90,7 @@ const ARTIFACT_TRANSITIONS = deepFreeze({
90
90
  backlog: ["proposed", "active", "cancelled"], proposed: ["active", "cancelled"], active: ["paused", "completed", "cancelled"], paused: ["active", "cancelled"]
91
91
  },
92
92
  task: {
93
- backlog: ["proposed", "running", "cancelled"], proposed: ["running", "cancelled"], running: ["validating", "failed", "blocked", "cancelled"], validating: ["learning", "failed", "blocked"], learning: ["completed", "failed", "blocked"], partial: ["running", "cancelled"], failed: ["running", "cancelled"], blocked: ["running", "cancelled"]
93
+ backlog: ["proposed", "in_progress", "running", "cancelled"], proposed: ["in_progress", "running", "cancelled"], in_progress: ["completed", "failed", "blocked", "cancelled"], running: ["validating", "completed", "failed", "blocked", "cancelled"], validating: ["learning", "completed", "failed", "blocked"], learning: ["completed", "failed", "blocked"], partial: ["in_progress", "running", "cancelled"], failed: ["in_progress", "running", "cancelled"], blocked: ["in_progress", "running", "cancelled"]
94
94
  },
95
95
  sprint: {
96
96
  proposed: ["running", "cancelled"], running: ["partial", "completed", "blocked", "cancelled"], partial: ["running", "completed", "cancelled"], blocked: ["running", "cancelled"]
@@ -108,7 +108,7 @@ const ARTIFACT_TRANSITIONS = deepFreeze({
108
108
  const STRUCTURAL_RELATIONS = deepFreeze({
109
109
  feature: { targetKind: "feature", cardinality: "0..1", meaning: "long-lived initiative containing the artifact" },
110
110
  sprint: { targetKind: "sprint", cardinality: "0..1", meaning: "optional delivery batch containing a Task or Run" },
111
- task: { targetKind: "task", cardinality: "1 for Run; otherwise 0..1", requiredFor: ["run"], meaning: "atomic work executed or reviewed by the artifact" }
111
+ task: { targetKind: "task", cardinality: "0..1", meaning: "atomic work executed or reviewed by the artifact" }
112
112
  });
113
113
 
114
114
  const SCALAR_FIELDS = deepFreeze({
@@ -120,9 +120,9 @@ const SCALAR_FIELDS = deepFreeze({
120
120
 
121
121
  const TRUTH_OWNERSHIP = deepFreeze({
122
122
  feature: { question: "Why does this initiative exist?", truth: "initiative purpose, scope, dependencies, and lifecycle" },
123
- task: { question: "What approved atomic outcome is intended?", truth: "scope, acceptance criteria, approval, and intended status" },
124
- sprint: { question: "When are related Tasks grouped?", truth: "timebox or delivery-batch membership; never execution history" },
125
- run: { question: "How did one execution attempt actually happen?", truth: "append-only execution events, evidence, result, and attempt number" },
123
+ task: { question: "What concrete outcome is intended?", truth: "scope, owner-defined sections, links, and status" },
124
+ sprint: { question: "Which Tasks are grouped for this delivery?", truth: "timebox or delivery-batch membership; may be feature, fix, or maintenance" },
125
+ run: { question: "What happened while executing a Task or Sprint?", truth: "optional human-readable execution record and outcome" },
126
126
  review: { question: "What independent validation was performed?", truth: "scoped findings, checks, evidence, and verdict" },
127
127
  knowledge: { question: "What verified project fact is reusable?", truth: "approved evidence-backed fact and validity" },
128
128
  decision: { question: "What normative choice constrains future work?", truth: "decision, rationale, validity, and lifecycle" },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "scrumrun",
3
- "version": "3.1.2",
4
- "description": "Evidence-driven Agile runtime and semantic project memory for AI coding agents.",
3
+ "version": "4.0.0",
4
+ "description": "Markdown-first Agile memory and guardrails for AI coding agents.",
5
5
  "bin": {
6
6
  "scrumrun": "bin/scrumrun.js",
7
7
  "sr-claude": "bin/claude-install.js"
@@ -69,7 +69,7 @@ Every artifact also requires \`id\`, \`kind\`, \`status\`, \`created\`, \`update
69
69
  |---|---|---|---|
70
70
  ${relationRows.join("\n")}
71
71
 
72
- Task is the atomic unit. A Task may have zero or one Sprint. A Task may have many Runs, but every Run belongs to exactly one Task and has a monotonically increasing attempt number within that Task. Sprint membership is authoritative on \`Task.sprint\`; a Sprint's \`## Tasks\` list is a human-readable projection that must agree with it.
72
+ Task is the atomic unit. A Task may have zero or one Sprint. A Run is optional Markdown history and may reference either a Task or a Sprint; it never controls Task status in Markdown-first work. Sprint membership is authoritative on \`Task.sprint\`; a Sprint's \`## Tasks\` list is a human-readable projection that must agree with it. Additional owner-defined relations such as \`depends_on: [TASK-014, DEC-018]\` are preserved as local Markdown graph data.
73
73
 
74
74
  ## Scalar constraints
75
75
 
@@ -85,7 +85,7 @@ Newly authored Runs use \`ledger: ${RUN_LEDGER_VERSION}\`. Their \`## Events\` s
85
85
 
86
86
  Every event requires \`schema\`, \`id\`, contiguous \`sequence\`, RFC3339 \`occurred_at\`, \`timestamp_precision\`, \`actor\`, \`from\`, \`to\`, \`reason\`, and structured \`evidence\`. Event types are ${RUN_EVENT_TYPES.map((value) => `\`${value}\``).join(", ")}. Evidence kinds are ${RUN_EVIDENCE_KINDS.map((value) => `\`${value}\``).join(", ")}.
87
87
 
88
- A native ledger begins with \`created → executing\`; an evidenced migration \`snapshot\` may establish one historical baseline without inventing missing transitions. Event order, transition legality, final status, updated date, and completion evidence are machine-validated. Run owns the event history; Task stores its intended scope and synchronized current status without copying Run events.
88
+ A native ledger begins with \`created → executing\`; an evidenced migration \`snapshot\` may establish one historical baseline without inventing missing transitions. Event order, transition legality, final status, updated date, and completion evidence are machine-validated when a strict audit Run is used. Run owns optional event history; Task Markdown owns the delivered scope and status in normal work.
89
89
 
90
90
  ## Truth questions
91
91
 
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "method": "2.0.0",
3
3
  "layout": "v2",
4
+ "workflow": {
5
+ "daily": "markdown-first"
6
+ },
4
7
  "paths_schema": 1,
5
8
  "paths": {
6
9
  "guardrails": "guardrails.md",
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md - {{PROJECT_NAME}}
2
2
 
3
- ## ScrumRun 3.1Markdown-first
3
+ ## ScrumRun 4.0execution-first Markdown
4
4
 
5
5
  This project uses ScrumRun. The method is mandatory; the direct CLI is `scrumrun <noun> <subject> <action>`. `/sc` is only an optional client shortcut.
6
6
 
@@ -15,18 +15,24 @@ Natural-language product requests begin with a read-only understanding pass. Bef
15
15
 
16
16
  After approval:
17
17
 
18
- - Task is the atomic work item; create or refine its Markdown directly, define its `## Acceptance Criteria`, and retain a short `## Technical Summary` / `## Follow-ups` handoff;
18
+ - execute continuously until the approved Task is delivered: keep working through discover → implement → verify → fix → verify. A progress report is allowed only when the owner asks for status and must be followed immediately by more execution; it never closes the workflow. Do not stop to send an inventory, a progress report, a decomposition, or a list of work still to do. A missing implementation found during the work remains work to do now, not a follow-up, a “next step”, or a reason to reply. Stop only for an owner decision, external access, an explicit Guardrail, a security/secret risk, destructive work without approval, or an unmet required Acceptance Criterion;
19
+ - Task is the atomic work item; create or refine its Markdown directly, define a short `## Done when` delivery contract, and retain a short `## Completion` / `## Follow-ups` handoff;
20
+ - you may decompose implementation privately or add linked child Tasks when needed, but do not make the owner manage that decomposition and do not stop after planning it;
19
21
  - validation is scoped: only a test/review/environment explicitly required by the owner, the Task's Acceptance Criteria, or an active Guardrail can block completion; a missing optional E2E suite is a documented follow-up/risk, never a reason to fail an otherwise accepted Task;
20
22
  - Feature and Sprint remain useful organization, but are optional; create them only when they clarify real initiative or timebox context;
21
23
  - Sprint is only a real timebox/batch of Tasks;
22
24
  - Run is an optional audit/handoff record, never an administrative prerequisite to start, amend, or complete a Task; preserve useful prior attempts but do not let missing/invalid Run metadata stop work;
23
- - record a `## Technical Summary` at completion so the next agent inherits what was done; record optional missing coverage in `## Follow-ups`;
25
+ - only claim a condition validated when the check actually covers that condition; a narrow checker never proves a broad delivery claim. Record a `## Completion` at completion so the next agent inherits what was done; `## Follow-ups` may contain only work outside the approved `## Done when`, never unfinished acceptance work;
24
26
  - work directly in code and Task Markdown after approval; do not call `npx scrumrun@latest` or normal `scrumrun plan/run` commands during execution;
25
27
  - use the CLI only for `init`, `update --project`, `migrate`, `repair`, `doctor`, reports, or release checks. It audits/repairs the folder; it does not own the daily workflow;
26
28
  - never invoke `plan run --fail`, `--block`, `--retry`, `--finalize`, `--complete`, `--validate`, or `plan task --start` in normal work. A failed legacy Run due to administrative state remains historical; write the corrected delivery outcome directly in the Task instead;
27
- - learning proposes evidence-backed Knowledge, Decisions, or candidate Insights when the work reveals reusable context;
29
+ - learning proposes evidence-backed Knowledge, Decisions, or candidate Insights after delivery, or only when it materially helps the current implementation; it never interrupts execution;
28
30
  - guardrails remain mandatory: stop only for an explicit Guardrail, security/secret risk, destructive action without approval, or an unmet required Acceptance Criterion. Status vocabulary, missing Runs, unavailable optional tests, and stale generated state are warnings to reconcile, not blockers.
29
31
 
32
+ `core.md` and `guardrails.md` are sealed policy. Never edit either during a product Task. A policy change requires an explicit owner request; after review, seal it at the maintenance edge with `scrumrun update --project --seal-policy`.
33
+
34
+ Artifacts are local Markdown connected by stable IDs and relative links. Preserve any owner-defined frontmatter and sections in a Task. A Guardrail may require sections such as `## Migration Plan`, `## Rollback`, or `## Guardrail Evidence`; add them only to the affected Task.
35
+
30
36
  Never bypass guardrails, overwrite owner work, treat generated state/cache as truth, auto-confirm AI knowledge, auto-migrate a v1 project, or print vault values.
31
37
 
32
38
  Never use `npx scrumrun@latest` in the normal work loop. If the installed CLI is unavailable, stop and report that blocker rather than substituting a network command.
@@ -1,6 +1,6 @@
1
1
  # AGENTS.md - {{PROJECT_NAME}}
2
2
 
3
- ## ScrumRun 3.1 lean read policy — Markdown-first
3
+ ## ScrumRun 4.0 lean read policy — execution-first Markdown
4
4
 
5
5
  This project stores the complete ScrumRun v2 truth but uses a bounded default read path:
6
6
 
@@ -11,12 +11,16 @@ This project stores the complete ScrumRun v2 truth but uses a bounded default re
11
11
 
12
12
  Do not scan every Task, Run, Sprint, Feature, or Memory file by default. Generated `state.md`, `map.md`, and `.cache/` guide retrieval but never override canonical Markdown.
13
13
 
14
- Natural-language product work begins as a read-only understanding pass. Explicit approval authorizes direct work in source files and `.scrumrun/` Markdown. Define the Task's `## Acceptance Criteria` before execution and record a `## Technical Summary` at completion. A Run is optional handoff/audit context, not a state machine that may prevent starting, amending, or completing work. A Sprint exists only for a real batch/timebox.
14
+ Natural-language product work begins as a read-only understanding pass. Explicit approval authorizes direct work in source files and `.scrumrun/` Markdown. Execute continuously until the approved Task is delivered: keep working through discover → implement → verify → fix → verify. A progress report is allowed only when the owner asks for status and must be followed immediately by more execution; it never closes the workflow. Do not stop to provide an inventory, a partial progress report, or a list of remaining work. A missing implementation found during the work remains work to do now, not a follow-up or “next step”. Define a short `## Done when` delivery contract, record `## Completion` only at the end, and never move unfinished contract work to `## Follow-ups` without explicit owner approval. A Run is optional handoff/audit context, not a state machine that may prevent starting, amending, or completing work. A Sprint exists only for a real batch/timebox.
15
15
 
16
16
  Guardrails are mandatory, but administrative state is not: block only for an explicit Guardrail, security/secret risk, destructive action without approval, or an unmet required Acceptance Criterion. Missing Runs, invalid legacy status vocabulary, stale generated views, and optional unrun tests are warnings to reconcile in Markdown. Record meaningful optional coverage gaps under `## Follow-ups`; they do not fail a delivered Task.
17
17
 
18
18
  `.scrumrun/guardrails.md` is canonical policy. Never bypass it, overwrite owner work, auto-confirm AI knowledge, auto-migrate v1 state, or print vault values.
19
19
 
20
+ `core.md` and `guardrails.md` are sealed policy. Never edit them during a product Task. A policy change requires an explicit owner request and `scrumrun update --project --seal-policy` after review.
21
+
22
+ Artifacts are local Markdown connected by stable IDs and relative links. Preserve owner-defined frontmatter and sections in each Task; Guardrails may require a section only on affected Tasks.
23
+
20
24
  Use the installed CLI only for `init`, `update --project`, `migrate`, `repair`, `doctor`, reports, and release checks. For daily product work, follow `.scrumrun/core.md` and edit the relevant Markdown directly.
21
25
 
22
26
  Never invoke `plan run --fail`, `--block`, `--retry`, `--finalize`, `--complete`, `--validate`, or `plan task --start` during normal work. If an old Run says failed for an administrative reason, leave it as history and record the actual delivered outcome in the Task's Technical Summary and Follow-ups.
@@ -3,7 +3,9 @@ name: scrumrun
3
3
  description: Use when initializing or migrating ScrumRun, handling product requests, planning or executing Tasks/Sprints/Features/Runs, managing guardrails or semantic memory, checking status, and running reviews.
4
4
  ---
5
5
 
6
- # ScrumRun 2.0
6
+ # ScrumRun 4.0 — execution-first Markdown
7
+
8
+ Package 4.0 implements the stable ScrumRun method contract 2.0.0.
7
9
 
8
10
  ScrumRun is an evidence-driven Agile runtime for AI agents. Its canonical shell command is:
9
11
 
@@ -36,9 +38,11 @@ Normal hot path:
36
38
  5. follow the briefing's pointers to only the relevant canonical artifacts; go deeper only when the briefing lacks what you need (`## Where to look`, `scrumrun knowledge study "<topic>"`);
37
39
  6. load `.scrumrun/core.md` when the method contract or an exceptional transition is needed.
38
40
 
39
- **Markdown is the daily runtime.** After approval, work directly in source files and the relevant `.scrumrun/` Markdown. Create/refine the Task, its acceptance criteria, technical summary, follow-ups, and optional Run handoff without waiting for a CLI transition. Do not invoke `npx scrumrun@latest` or normal `scrumrun plan/run` commands during execution. The CLI is optional maintenance for `init`, `update --project`, `migrate`, `repair`, `doctor`, reports, and release checks.
41
+ **Markdown is the daily runtime.** After approval, work directly in source files and the relevant `.scrumrun/` Markdown until the approved Task is delivered. Continue the full loop — discover → implement → verify → fix → verify — before responding. A progress report is allowed only when the owner asks for status and must be followed immediately by further execution; it never ends the Task. Do not stop to issue a progress report, inventory, decomposition, or list of remaining work; those are internal implementation steps. A missing implementation discovered in scope remains required work now, never a follow-up or a “next step”. Stop only for an owner decision, external access, an explicit Guardrail, security/secret risk, destructive work without approval, or an unmet required delivery criterion. Do not invoke `npx scrumrun@latest` or normal `scrumrun plan/run` commands during execution. The CLI is optional maintenance for `init`, `update --project`, `migrate`, `repair`, `doctor`, reports, and release checks.
42
+
43
+ **Do not block on administrative state.** A missing/invalid Run, legacy status vocabulary, stale generated view, or optional unrun test is a warning to reconcile in Markdown, not a reason to refuse productive work. Define a concise `## Done when` delivery contract. `## Follow-ups` is only for work outside that contract: never relabel an unfinished requirement as a follow-up without explicit owner approval. Optional E2E/integration/review coverage belongs there or in a risk note, never in a fabricated failed Run.
40
44
 
41
- **Do not block on administrative state.** A missing/invalid Run, legacy status vocabulary, stale generated view, or optional unrun test is a warning to reconcile in Markdown, not a reason to refuse productive work. Block only for an explicit Guardrail, security/secret risk, destructive action without approval, or an unmet required Acceptance Criterion. Optional E2E/integration/review coverage belongs in `## Follow-ups` or a risk note, never in a fabricated failed Run.
45
+ **A check must prove its claim.** A passing narrow checker does not prove a broader Task condition. If the task says no visible hardcoded literals, scan the relevant source, replace every in-scope match, and re-run that scan plus the build. Apply the same coverage rule to all completion claims.
42
46
 
43
47
  **Normal-operation command ban.** Do not invoke `scrumrun plan run --fail`, `--block`, `--retry`, `--finalize`, `--complete`, `--validate`, or `scrumrun plan task --start` during ordinary work. Those are optional strict-audit tools and cannot be used to decide whether a Task is delivered. If an old Run is already failed for an administrative reason, leave it as historical evidence, continue the Task directly, and write the corrected outcome in the Task's Technical Summary and Follow-ups.
44
48
 
@@ -104,11 +108,11 @@ During execution:
104
108
 
105
109
  1. keep the change inside the approved Task scope;
106
110
  2. preserve existing owner work and unrelated dirty files;
107
- 3. define or confirm the Task's `## Acceptance Criteria` before execution and check them off as evidence;
108
- 4. work normally: edit code and update the Task's `## Technical Summary`, `## Follow-ups`, and any Guardrail evidence required by an active rule;
111
+ 3. define or confirm the Task's short `## Done when` contract before execution and use it as the only delivery boundary;
112
+ 4. work normally and continuously. Privately decompose work or create linked child Tasks when useful, but do not return after planning; edit code until the contract is satisfied;
109
113
  5. validate in proportion to risk and against the acceptance criteria. Tests, reviews, and environments are required only when the owner, Acceptance Criteria, or an active Guardrail says so. Do not fail or block an otherwise accepted Task merely because an optional E2E/integration suite does not exist or was not run;
110
114
  6. run a configured reviewer only when a Guardrail requires it;
111
- 7. complete the Task directly in Markdown after the required work is satisfied; use CLI release/doctor/repair commands only when their audit or recovery value is wanted;
115
+ 7. complete the Task directly in Markdown after the required work is satisfied, adding a concise `## Completion`; use CLI release/doctor/repair commands only when their audit or recovery value is wanted;
112
116
  8. use path-scoped Mutation Gateway commands only when the owner explicitly requests strict execution.
113
117
 
114
118
  Never overwrite a prior attempt. Never mark work complete because time/token budget ended.
@@ -117,7 +121,7 @@ When work remains queued, the briefing may name the next backlog Task. The owner
117
121
 
118
122
  Every explicit Guardrail remains mandatory. In strict mode, the CLI final checkpoint fails closed on policy drift, protected-path changes, unsafe symlinks, unscannable content, newly introduced secret-like content, or missing Guardrail Evidence. The ignored permit cache is disposable; deleting it invalidates outstanding strict-mode permits and never creates authority.
119
123
 
120
- Task Markdown is the daily operational handoff authority. A structured Run is optional strict audit history only. Early v2 prose Runs may be repaired/migrated explicitly, but their state never overrides the Task's direct handoff or blocks approved work.
124
+ Task Markdown is the daily operational handoff authority. A structured Run is optional strict audit history only. `core.md` and `guardrails.md` are sealed policy: never edit either during product work. A policy change requires an explicit owner request and the owner seals reviewed changes with `scrumrun update --project --seal-policy`. Early v2 prose Runs may be repaired/migrated explicitly, but their state never overrides the Task's direct handoff or blocks approved work.
121
125
 
122
126
  Linked canonical writes use the ignored durable transaction journal. An interrupted prepared mutation rolls back before the next approved mutation; a committed journal is verified and finalized. Audit remains read-only and reports pending recovery. Use `doctor --recover` only when explicitly requested, and never overwrite bytes changed after interruption.
123
127
 
package/types/index.d.ts CHANGED
@@ -21,7 +21,7 @@ export type ArtifactKind =
21
21
 
22
22
  export type ArtifactStatus =
23
23
  | "backlog" | "proposed" | "active" | "completed" | "paused" | "cancelled"
24
- | "running" | "validating" | "learning" | "partial" | "failed" | "blocked"
24
+ | "running" | "in_progress" | "validating" | "learning" | "partial" | "failed" | "blocked"
25
25
  | "candidate" | "approved" | "rejected" | "deprecated" | "invalidated"
26
26
  | "open" | "resolved" | "confirmed" | "stale" | "archived" | "executing" | "passed";
27
27