scrumrun 3.1.1 → 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 +21 -0
- package/CORE.md +13 -5
- package/README.md +31 -16
- package/SPEC.md +7 -3
- package/bin/scrumrun.js +40 -7
- package/docs/COMMANDS.md +10 -8
- package/docs/ENTITY-MODEL.md +17 -14
- package/docs/QUICKSTART.md +21 -19
- package/docs/SCHEMA.md +10 -10
- package/lib/commands/manifest.js +9 -9
- package/lib/commands/render.js +3 -2
- package/lib/runtime/briefing.js +29 -0
- package/lib/runtime/orchestrator.js +4 -4
- package/lib/runtime/policy-integrity.js +83 -0
- package/lib/v2/artifacts.js +9 -0
- package/lib/v2/conformance.js +18 -16
- package/lib/v2/paths.js +2 -1
- package/lib/v2/schema.js +7 -7
- package/package.json +2 -2
- package/scripts/generate-contract-docs.js +2 -2
- package/templates/project/.scrumrun/method.json +3 -0
- package/templates/project/AGENTS.md +10 -4
- package/templates/project-lean/AGENTS.md +6 -2
- package/templates/shared/skills/scrumrun/SKILL.md +11 -7
- package/types/index.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,32 @@ 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
|
+
|
|
21
|
+
## 3.1.2 - 2026-08-31
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **Mechanical strict-audit gate.** The CLI now refuses Task start/retry and every Run state transition unless `--strict` is explicitly present. This prevents a normal agent loop from creating failed/blocked administrative Runs even if it ignores the Markdown-first guidance.
|
|
26
|
+
|
|
7
27
|
## 3.1.1 - 2026-08-31
|
|
8
28
|
|
|
9
29
|
### Fixed
|
|
10
30
|
|
|
11
31
|
- **No strict-Run commands in daily work.** Generated Core and agent instructions now explicitly prohibit `plan run --fail|--block|--retry|--finalize|--complete|--validate` and `plan task --start` in normal operation. A legacy Run incorrectly failed for administrative reasons stays as history; the Task's direct Markdown handoff records the real result.
|
|
32
|
+
- **CLI backstop.** Task start/retry and Run state-changing commands now require an explicit `--strict`, so an agent that ignores the guidance cannot accidentally create another failed/blocked administrative Run.
|
|
12
33
|
|
|
13
34
|
## 3.1.0 - 2026-08-31
|
|
14
35
|
|
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,
|
|
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
|
|
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
|
-
**
|
|
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
|
|
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:** `
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
25
|
+
SPRINT-012 (type: fix)
|
|
23
26
|
└── TASK-018
|
|
24
|
-
├──
|
|
25
|
-
├──
|
|
26
|
-
├──
|
|
27
|
-
└──
|
|
27
|
+
├── feature → FEAT-003
|
|
28
|
+
├── depends_on → TASK-014, DEC-018
|
|
29
|
+
├── guardrails → GR-004
|
|
30
|
+
└── run → RUN-044 (optional)
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
A Task does not need a Sprint. A
|
|
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
|
|
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 `##
|
|
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
|
|
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,8 +102,14 @@ 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
|
|
|
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.
|
|
112
|
+
|
|
104
113
|
Each optional structured Run contains a machine-validated event ledger. It remains useful for strict audit/release work, but daily history can stay as concise, human-readable Task handoff Markdown.
|
|
105
114
|
|
|
106
115
|
Linked Task/Run writes use a durable ignored transaction journal. Captured failures roll back immediately; interrupted operations are recovered byte-exactly on retry or through explicit `doctor --recover`. Read-only audit reports pending recovery and never repairs state silently.
|
|
@@ -159,12 +168,18 @@ It is progressive disclosure: the briefing is enough for most work; the agent fo
|
|
|
159
168
|
|
|
160
169
|
## Migrating an ongoing v1 project
|
|
161
170
|
|
|
162
|
-
Update the client integrations. For an existing project, refresh the
|
|
171
|
+
Update the client integrations. For an existing project, refresh the execution-first guidance explicitly:
|
|
163
172
|
|
|
164
173
|
```bash
|
|
165
174
|
scrumrun update --project
|
|
166
175
|
```
|
|
167
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
|
+
|
|
168
183
|
This shows the source inventory, proposed mappings, and blockers without changing project data. Apply only the verified plan with:
|
|
169
184
|
|
|
170
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
|
|
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
|
|
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
|
|
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"));
|
|
@@ -1308,6 +1319,7 @@ function runTransitionOptions(args) {
|
|
|
1308
1319
|
let summary = null;
|
|
1309
1320
|
for (let index = 2; index < args.length; index++) {
|
|
1310
1321
|
const token = args[index];
|
|
1322
|
+
if (token === "--strict") continue;
|
|
1311
1323
|
const value = args[index + 1] && !args[index + 1].startsWith("--") ? args[index + 1] : null;
|
|
1312
1324
|
if (token === "--note" || token === "--actor" || token === "--at" || token === "--evidence" || token === "--summary" || evidenceFlags.has(token)) {
|
|
1313
1325
|
if (!value) throw new Error(`${token} requires a value.`);
|
|
@@ -1333,6 +1345,11 @@ function runTransitionOptions(args) {
|
|
|
1333
1345
|
return { note: note || noteParts.join(" ").trim() || null, evidence, actor, occurredAt, summary };
|
|
1334
1346
|
}
|
|
1335
1347
|
|
|
1348
|
+
function requireStrictAudit(args, action) {
|
|
1349
|
+
if (args.includes("--strict")) return;
|
|
1350
|
+
throw new Error(`${action} is disabled in Markdown-first daily work. Update the Task Markdown directly; use --strict only for an owner-requested audit.`);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1336
1353
|
function removeOptionPairs(args, names) {
|
|
1337
1354
|
const hidden = new Set(names);
|
|
1338
1355
|
const next = [];
|
|
@@ -1470,6 +1487,7 @@ function executeRootRoute(route) {
|
|
|
1470
1487
|
return;
|
|
1471
1488
|
}
|
|
1472
1489
|
if (noun === "plan" && subject === "task" && routeArgs[0] === "--retry") {
|
|
1490
|
+
requireStrictAudit(routeArgs, "Task retry");
|
|
1473
1491
|
const result = retryTask(process.cwd(), routeArgs[1], { reassign: routeArgs.includes("--reassign") });
|
|
1474
1492
|
console.log(`Created retry ${result.run.id} for ${result.task.id} (attempt ${result.run.attempt}).`);
|
|
1475
1493
|
return;
|
|
@@ -1486,6 +1504,7 @@ function executeRootRoute(route) {
|
|
|
1486
1504
|
return;
|
|
1487
1505
|
}
|
|
1488
1506
|
if (noun === "plan" && subject === "task" && routeArgs[0] === "--start") {
|
|
1507
|
+
requireStrictAudit(routeArgs, "Task start");
|
|
1489
1508
|
let target = routeArgs[1];
|
|
1490
1509
|
if (!target) {
|
|
1491
1510
|
const repository = new ArtifactRepository(projectFile());
|
|
@@ -1610,9 +1629,10 @@ function executeRootRoute(route) {
|
|
|
1610
1629
|
}
|
|
1611
1630
|
if (noun === "plan" && subject === "run") {
|
|
1612
1631
|
if (routeArgs[0] === "--finalize") {
|
|
1632
|
+
requireStrictAudit(routeArgs, "Run finalization");
|
|
1613
1633
|
const runId = routeArgs[1];
|
|
1614
1634
|
if (!runId) throw new Error("--finalize requires RUN-NNN.");
|
|
1615
|
-
const result = finalizeRun(process.cwd(), runId, runTransitionOptions(routeArgs
|
|
1635
|
+
const result = finalizeRun(process.cwd(), runId, runTransitionOptions(routeArgs));
|
|
1616
1636
|
console.log(`${result.run.id}: completed; ${result.task.id}: completed. Final session audit verified ${result.changes} change(s).`);
|
|
1617
1637
|
if (result.resolved.length) console.log(`Guardrails verified: ${result.resolved.join(", ")}.`);
|
|
1618
1638
|
if (result.learning && result.learning.created.length) console.log(`Learning candidates: ${result.learning.created.join(", ")}.`);
|
|
@@ -1654,6 +1674,7 @@ function executeRootRoute(route) {
|
|
|
1654
1674
|
"--block": "blocked"
|
|
1655
1675
|
};
|
|
1656
1676
|
if (transitions[routeArgs[0]]) {
|
|
1677
|
+
requireStrictAudit(routeArgs, `Run transition ${routeArgs[0]}`);
|
|
1657
1678
|
const result = transitionRun(process.cwd(), routeArgs[1], transitions[routeArgs[0]], runTransitionOptions(routeArgs));
|
|
1658
1679
|
console.log(`${result.run.id}: ${result.run.status}; ${result.task.id}: ${result.task.status}.`);
|
|
1659
1680
|
if (result.learning) {
|
|
@@ -1696,7 +1717,12 @@ function executeRootRoute(route) {
|
|
|
1696
1717
|
}
|
|
1697
1718
|
if (noun === "config" && subject === "update") {
|
|
1698
1719
|
const target = ["all", "codex", "opencode", "claude"].includes(routeArgs[0]) ? routeArgs[0] : "all";
|
|
1699
|
-
return updateInstallation(target, {
|
|
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
|
+
});
|
|
1700
1726
|
}
|
|
1701
1727
|
if (noun === "config" && subject === "init") {
|
|
1702
1728
|
const localMode = routeArgs.includes("--local");
|
|
@@ -2312,6 +2338,8 @@ function promptCommand(parts) {
|
|
|
2312
2338
|
|
|
2313
2339
|
function initProject({ force, mode, agentHint, lean }) {
|
|
2314
2340
|
const cwd = process.cwd();
|
|
2341
|
+
const marker = path.join(cwd, ".scrumrun", "method.json");
|
|
2342
|
+
const markerExisted = fs.existsSync(marker);
|
|
2315
2343
|
const vars = {
|
|
2316
2344
|
PROJECT_NAME: path.basename(cwd),
|
|
2317
2345
|
DATE: new Date().toISOString().slice(0, 10)
|
|
@@ -2322,6 +2350,10 @@ function initProject({ force, mode, agentHint, lean }) {
|
|
|
2322
2350
|
|
|
2323
2351
|
results.push(...copyDir(path.join(projectTemplate, ".scrumrun"), path.join(cwd, ".scrumrun"), { force, vars }));
|
|
2324
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
|
+
}
|
|
2325
2357
|
results.push(ensureProjectIgnore(cwd));
|
|
2326
2358
|
|
|
2327
2359
|
if (mode === "shared" || agentHint) {
|
|
@@ -2601,8 +2633,9 @@ function doctor(target = "all", { compatibility = false, strict = false, recover
|
|
|
2601
2633
|
console.log(`miss ScrumRun project audit: ${scrumDir}`);
|
|
2602
2634
|
} else {
|
|
2603
2635
|
const audit = auditProject(process.cwd());
|
|
2604
|
-
|
|
2605
|
-
|
|
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)`);
|
|
2606
2639
|
for (const item of audit.findings) console.log(` ${item.severity} ${item.code}: ${item.message}`);
|
|
2607
2640
|
}
|
|
2608
2641
|
}
|
|
@@ -2623,7 +2656,7 @@ if (!command || command === "--help" || command === "-h") {
|
|
|
2623
2656
|
console.log(`ScrumRun ${version}`);
|
|
2624
2657
|
} else if (command === "install" || command === "update") {
|
|
2625
2658
|
const target = ["all", "codex", "opencode", "claude"].includes(args[1]) ? args[1] : "all";
|
|
2626
|
-
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") });
|
|
2627
2660
|
else install(target, true, { compatibility: false });
|
|
2628
2661
|
} else if (command === "sc") {
|
|
2629
2662
|
runRoot(args.slice(1));
|
package/docs/COMMANDS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ScrumRun
|
|
1
|
+
# ScrumRun 4.0 Command Reference
|
|
2
2
|
|
|
3
3
|
The canonical grammar is:
|
|
4
4
|
|
|
@@ -13,25 +13,27 @@ Use `.scrumrun/` Markdown for normal project work. `/sc` and the installed CLI a
|
|
|
13
13
|
```text
|
|
14
14
|
scrumrun plan intake <request>
|
|
15
15
|
scrumrun plan intake --approve <token>
|
|
16
|
-
scrumrun plan task --add|--list|--show|--run|--audit|--cancel|--retry
|
|
16
|
+
scrumrun plan task --add|--list|--show|--run|--audit|--cancel|--retry --strict
|
|
17
17
|
scrumrun plan task --amend TASK-NNN [--title "..."] [--request "..."] [--acceptance "..."] [--section "Heading=content"] [--type fix|task|feature|docs|discovery] [--feature FEAT-NNN|null] [--sprint SPRINT-NNN|null]
|
|
18
18
|
scrumrun plan sprint --add|--list|--show|--start|--complete|--block
|
|
19
19
|
scrumrun plan sprint --amend SPRINT-NNN [--title "..."] [--timebox "..."] [--exit-gate "..."] [--section "Heading=content"]
|
|
20
20
|
scrumrun plan feature --add|--list|--show|--activate|--complete
|
|
21
21
|
scrumrun plan feature --amend FEAT-NNN [--title "..."] [--purpose "..."] [--exit-criteria "..."] [--section "Heading=content"]
|
|
22
|
-
scrumrun plan run --list|--show|--validate|--learn|--complete|--resume|--fail|--block [--note] [typed evidence flags]
|
|
23
|
-
scrumrun plan run --finalize RUN-NNN [--summary "technical recap"] [--note]
|
|
22
|
+
scrumrun plan run --list|--show|--validate|--learn|--complete|--resume|--fail|--block --strict [--note] [typed evidence flags]
|
|
23
|
+
scrumrun plan run --finalize RUN-NNN --strict [--summary "technical recap"] [--note]
|
|
24
24
|
scrumrun plan run --authorize-mutation RUN-NNN --path <relative-path> [--path ...]
|
|
25
25
|
scrumrun plan run --record-mutation RUN-NNN --permit MUT-id [--note] [--actor]
|
|
26
26
|
scrumrun plan run --satisfy-guardrail RUN-NNN --guardrail GR-NNN [typed evidence flags]
|
|
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
|
|
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
|
+
|
|
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.
|
|
31
33
|
|
|
32
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.
|
|
33
35
|
|
|
34
|
-
Every new Task starts with
|
|
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.
|
|
35
37
|
|
|
36
38
|
## What can be changed
|
|
37
39
|
|
|
@@ -80,14 +82,14 @@ scrumrun review release --run
|
|
|
80
82
|
```text
|
|
81
83
|
scrumrun config project --show|--language|--interaction|--approval|--quick-tasks
|
|
82
84
|
scrumrun config init --local|--shared|--lean|--no-agent-hint|--force
|
|
83
|
-
scrumrun config update [all|codex|opencode|claude] [--project] [--migrate]
|
|
85
|
+
scrumrun config update [all|codex|opencode|claude] [--project] [--seal-policy] [--migrate]
|
|
84
86
|
scrumrun config migrate --to 2 --dry-run|--apply|--rollback
|
|
85
87
|
scrumrun config doctor [all|codex|opencode|claude] [--strict] [--recover]
|
|
86
88
|
scrumrun config uninstall --force
|
|
87
89
|
scrumrun config help <topic>
|
|
88
90
|
```
|
|
89
91
|
|
|
90
|
-
Top-level CLI aliases (`init`, `update`, `migrate`, `doctor`, `uninstall`, `status`) remain available for shell automation. `update --project` refreshes the packaged
|
|
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.
|
|
91
93
|
|
|
92
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.
|
|
93
95
|
|
package/docs/ENTITY-MODEL.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ScrumRun
|
|
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
|
-
|
|
|
11
|
-
|
|
|
12
|
-
| Run |
|
|
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
|
-
|
|
19
|
+
SPRINT-012 (type: fix)
|
|
17
20
|
└── TASK-018
|
|
18
|
-
├──
|
|
19
|
-
├──
|
|
20
|
-
├──
|
|
21
|
-
└──
|
|
21
|
+
├── feature → FEAT-003
|
|
22
|
+
├── depends_on → TASK-014, DEC-018
|
|
23
|
+
├── guardrails → GR-004
|
|
24
|
+
└── run → RUN-044 (optional)
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
Task is
|
|
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
|
|
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
|
|
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 → implement → verify → fix → 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.
|
|
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
|
|
package/docs/QUICKSTART.md
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# Quickstart
|
|
2
2
|
|
|
3
|
-
Get from "never heard of it" to your first
|
|
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
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
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
|
|
68
|
+
Only then does the Task become approved. The agent executes it directly in code and Markdown; a Run is optional.
|
|
68
69
|
|
|
69
|
-
##
|
|
70
|
+
## Delivering the Task
|
|
70
71
|
|
|
71
|
-
The agent executes inside the approved scope
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
84
|
-
|
|
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:
|