@lumoai/cli 1.57.0 → 1.59.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.
Files changed (46) hide show
  1. package/assets/skill/SKILL.md +52 -130
  2. package/assets/skill/references/artifacts-figma.md +4 -3
  3. package/assets/skill/references/confirmation.md +131 -0
  4. package/assets/skill/references/criteria.md +60 -20
  5. package/assets/skill/references/doc-editing.md +11 -9
  6. package/assets/skill/references/docs.md +4 -3
  7. package/assets/skill/references/ideas.md +82 -0
  8. package/assets/skill/references/initiatives.md +28 -0
  9. package/assets/skill/references/memory.md +4 -2
  10. package/assets/skill/references/milestones.md +3 -2
  11. package/assets/skill/references/outcome.md +1 -14
  12. package/assets/skill/references/plan-runs.md +32 -0
  13. package/assets/skill/references/sessions.md +7 -5
  14. package/assets/skill/references/sprints.md +18 -17
  15. package/assets/skill/references/task-context.md +1 -1
  16. package/assets/skill/references/task-deps.md +4 -3
  17. package/assets/skill/references/tasks.md +34 -2
  18. package/assets/skill/references/verify.md +46 -68
  19. package/assets/skill/references/worktree.md +13 -7
  20. package/dist/cli/src/commands/doc-delete.js +35 -23
  21. package/dist/cli/src/commands/doc-rebuild-source.js +16 -4
  22. package/dist/cli/src/commands/memory-rm.js +68 -10
  23. package/dist/cli/src/commands/milestone-delete.js +13 -10
  24. package/dist/cli/src/commands/outcome.js +0 -77
  25. package/dist/cli/src/commands/session-attach.js +8 -2
  26. package/dist/cli/src/commands/sprint-close.js +29 -9
  27. package/dist/cli/src/commands/sprint-delete.js +13 -10
  28. package/dist/cli/src/commands/sprint-show.js +3 -9
  29. package/dist/cli/src/commands/task-artifact-rm.js +58 -28
  30. package/dist/cli/src/commands/task-criteria-list.js +1 -4
  31. package/dist/cli/src/commands/task-criteria-set.js +3 -12
  32. package/dist/cli/src/commands/task-deps.js +20 -6
  33. package/dist/cli/src/commands/task-status.js +165 -110
  34. package/dist/cli/src/commands/task-update.js +129 -0
  35. package/dist/cli/src/commands/verify.js +22 -13
  36. package/dist/cli/src/commands/worktree-rm.js +35 -7
  37. package/dist/cli/src/index.js +47 -47
  38. package/dist/cli/src/lib/blocked-error.js +178 -0
  39. package/dist/cli/src/lib/confirmation.js +89 -0
  40. package/dist/cli/src/lib/hook-runner.js +23 -11
  41. package/dist/shared/src/referent-kind.js +31 -1
  42. package/dist/shared/src/security-scan.js +29 -0
  43. package/package.json +1 -1
  44. package/assets/skill/references/fidelity.md +0 -32
  45. package/dist/cli/src/commands/fidelity.js +0 -108
  46. package/dist/cli/src/commands/verdict.js +0 -189
@@ -9,9 +9,38 @@ The acceptance contract is a small set of structured criteria the task's work is
9
9
  If `lumo task context` / session-start shows the draft reminder ("This task has no acceptance criteria yet. …") instead of a contract, you MUST draft and submit criteria before starting implementation:
10
10
 
11
11
  1. Read the task description, comments, linked resources, and memory first — the contract distills what "done" means, so understand the task before writing it.
12
- 2. Draft **3–7 criteria** for a typical multi-file task (soft range — the server warns outside it but never rejects; if you genuinely need more, merge related checks instead). Scale the count down for small tasks (see "Scale the contract to the task size").
12
+ 2. Draft **3–7 criteria** for a typical multi-file task (drafting guidance only — the server enforces no count; if you genuinely need more, merge related checks instead). Scale the count down for small tasks (see "Scale the contract to the task size").
13
13
  3. `lumo task criteria set <task> --file <criteria.json>` — submit.
14
14
 
15
+ ### The reference-class block (outside view) — LUM-497
16
+
17
+ Below the draft reminder you may see a `### Reference class (outside view)` block: mechanical statistics over **similar delivered tasks** — the send-back reasons they hit, how often their contract was still being written after work started, and the boundary crossings they tripped. It exists because an agent drafting its own acceptance criteria is systematically optimistic: you write down what you intend to build, not what tasks like this one historically got sent back for.
18
+
19
+ ```
20
+ ### Reference class (outside view)
21
+
22
+ Based on: 14 delivered tasks in milestone "Trust and cognitive load"
23
+
24
+ · Most common send-back reasons: evidence insufficient 5/14 · work did not match the criterion 3/14
25
+ · Contract still being written after work started: 9/14 deliveries
26
+ · Most common boundary crossing: edited a file a checkpointer depends on 3/14
27
+
28
+ Tasks here most often come back for insufficient evidence — what will your key criteria point at as proof?
29
+ ```
30
+
31
+ **How to use it:** read the failure modes, then ask which of them this task can plausibly hit, and let that change what you write. "Evidence insufficient" leads the class → decide what your key criteria will actually point at as proof. "Work did not match the criterion" leads → check that your statements describe outcomes rather than the steps you plan to take.
32
+
33
+ **How NOT to use it — this is the failure mode the block itself is most likely to cause:** do not treat the lines as a checklist to be "covered". Adding one criterion per listed failure mode, or setting `evidenceRequired` on everything because evidence leads the distribution, inflates the criterion count without adding information and taxes every verification round. The trailing line is deliberately a **question, not an instruction** — answer it for this task.
34
+
35
+ Reading the numbers honestly:
36
+
37
+ - Counts are **raw fractions over a small class** (`5/14`), never percentages, on purpose — `5/14` is a handful of tasks, not a rate. Weight them accordingly.
38
+ - The block names its own class and sample size (`Based on: N delivered tasks in <scope>`) — a milestone-level class is far more relevant to your task than a team-level fallback. Check which one you got.
39
+ - **`Insufficient sample: …` is a correct, deliberate output**, not a failure or a missing feature. It means no scope reached the minimum class size (the block states the floor in its own message), and a distribution over fewer tasks would read as evidence while carrying none. Draft from the task itself and move on.
40
+ - A class with no recorded send-backs, post-start contract edits or crossings says so explicitly. That is a stated fact about the class, not missing data.
41
+
42
+ The block is derived server-side from delivery history; it is not a claim by any agent, and there is nothing to reply to or act on beyond your own drafting.
43
+
15
44
  **The contract is editable until DONE — changes after work starts leave a recorded drift trail.** Behaviour changes at two thresholds tracked by `Task.workStartedAt` (set the first time the task leaves TODO; never resets even if the task bounces back to TODO):
16
45
 
17
46
  | Stage | `criteria set` resubmit behaviour |
@@ -60,20 +89,15 @@ The 3–7 range is calibrated for typical multi-file tasks. Criterion count must
60
89
 
61
90
  ### judgeSteps — agent-drafted judging steps for HUMAN criteria
62
91
 
63
- **`referentKind` — what the criterion anchors (required, and a real gate as of LUM-605):**
64
-
65
- Every criterion declares one `referentKind` — the only dimension that decides whether a PASS is independent or self-confirming. Required on every item (the API rejects a missing one with 400):
66
-
67
- - `EXTERNAL_FACT` — anchored on a fact the agent cannot author: a git SHA / diff, CI status, an HTTP probe, a DB row, `prisma migrate status`. **Only honest when the checkpointer actually invokes external tooling** (`git`/`gh`/`curl`/`psql`/…) AND its output or exit status reaches the verdict (piped into an assertion, captured in `$(…)`, or the terminal command whose exit IS the verdict). A no-op or output-discarded external command (`git --version && cat frozen.txt | grep`) does **not** count.
68
- - `AGENT_CONSTRUCTED_STATE` — passes by checking output the agent itself produced: **your own jest/vitest/tsc/node/tsx tests, build, type-check**. This is the honest kind for almost every code task's checks. Green here is self-confirming — that's fine, just label it truthfully.
69
- - `PENDING_OUTCOME` — truth lands post-delivery (a downstream regression, a revert). Has no check today: it **cannot** be MACHINE (the API rejects PENDING_OUTCOME + MACHINE). Draft it HUMAN or leave it out of the encoded contract.
92
+ **`referentKind` — derived by the system, not declared (LUM-733):**
70
93
 
71
- **The gate (LUM-605):** declaring `EXTERNAL_FACT` + MACHINE on a checkpointer that doesn't ground external (e.g. `npx jest …`) is the LUM-601 fakeGit shape — it would launder a self-confirming green into a "verified external fact". The system now downgrades it to `UNVERIFIED_ASSERTION` and:
94
+ You do not declare a referent kind. The server derives it from the checkpointer at write time and stores the result:
72
95
 
73
- - at **`criteria set`** stores it but returns a non-rejecting warning naming the criterion (re-ground or re-declare);
74
- - at **`lumo verify`** a PASS on it is **blocked with 422 (no round burned)**; the round does not land and the task does not move to IN_REVIEW until you either re-ground the checkpointer against a real external fact, or honestly re-declare it `AGENT_CONSTRUCTED_STATE`. Both fixes are free (no round consumed).
96
+ - MACHINE + a checkpointer that actually **consumes** an external tool (`git`/`gh`/`curl`/`psql`/`prisma migrate status`…, its exit or output reaching the verdict) `EXTERNAL_FACT` — a fact the agent cannot author.
97
+ - MACHINE + anything else (`jest`/`vitest`/`tsc`/`node`/`tsx`, your own build or type-check) `AGENT_CONSTRUCTED_STATE` green is self-confirming, which is the honest kind for almost every code task's checks.
98
+ - HUMAN → no checkpointer to read; an optional `"referentKind": "EXTERNAL_FACT" | "AGENT_CONSTRUCTED_STATE"` is kept as-is, otherwise the row stays unclassified.
75
99
 
76
- Don't reach for `EXTERNAL_FACT` to look stronger a jest test is `AGENT_CONSTRUCTED_STATE`, full stop. Reserve `EXTERNAL_FACT` for checks that truly read external state, or use a HUMAN criterion for "a person ran the real system and observed X" (HUMAN is never mechanically downgraded).
100
+ A `referentKind` on a MACHINE item is accepted for backward compatibility and ignored. `PENDING_OUTCOME` is no longer a task-criterion kind (it remains on milestone exit criteria only) leave post-delivery truths out of the encoded contract. There is no verify-time gate to trip: because the kind follows the check, a jest-checked criterion can never be stored as an "external fact".
77
101
 
78
102
  A HUMAN criterion is judged by a person, not a checkpointer — so don't hand them a bare assertion ("the copy reads naturally") and make them reverse-engineer what to do. Attach **`judgeSteps`**: short, human-readable instructions the adjudication card renders verbatim (light markdown, URLs made clickable). Structured labour is yours; the human just follows the steps.
79
103
 
@@ -113,14 +137,12 @@ Two real-repo invariant examples — `prisma/migrations/` files never deleted (t
113
137
  {
114
138
  "statement": "No file under prisma/migrations/ is deleted by this change (vs origin/main)",
115
139
  "verifierType": "MACHINE",
116
- "checkpointer": "bash -c \"test -z \\\"$(git diff --diff-filter=D --name-only origin/main -- prisma/migrations/)\\\"\"",
117
- "referentKind": "EXTERNAL_FACT"
140
+ "checkpointer": "bash -c \"test -z \\\"$(git diff --diff-filter=D --name-only origin/main -- prisma/migrations/)\\\"\""
118
141
  },
119
142
  {
120
143
  "statement": "Live-doc keeps its table structure after the edit (no rows/headings dropped)",
121
144
  "verifierType": "MACHINE",
122
- "checkpointer": "npx tsx scripts/verify-live-doc.ts <docId> docs/live-docs/<file>.md",
123
- "referentKind": "AGENT_CONSTRUCTED_STATE"
145
+ "checkpointer": "npx tsx scripts/verify-live-doc.ts <docId> docs/live-docs/<file>.md"
124
146
  }
125
147
  ]
126
148
  ```
@@ -138,8 +160,7 @@ One invariant criterion is usually enough — it's the guardrail, not the whole
138
160
  {
139
161
  "statement": "PUT /api/tasks/[id]/criteria rejects a second AGENT_DRAFT submission with 409",
140
162
  "verifierType": "MACHINE",
141
- "checkpointer": "npx jest __tests__/task-criteria.service.test.ts -t 'agent lock'",
142
- "referentKind": "AGENT_CONSTRUCTED_STATE"
163
+ "checkpointer": "npx jest __tests__/task-criteria.service.test.ts -t 'agent lock'"
143
164
  },
144
165
  {
145
166
  "statement": "The criteria section reads naturally as part of the task statement",
@@ -151,7 +172,6 @@ One invariant criterion is usually enough — it's the guardrail, not the whole
151
172
  "statement": "Session-start injection shows the contract ahead of memory",
152
173
  "verifierType": "MACHINE",
153
174
  "checkpointer": "npx jest __tests__/cli/hook-runner-session-start-stdout.test.ts",
154
- "referentKind": "AGENT_CONSTRUCTED_STATE",
155
175
  "evidenceRequired": true
156
176
  }
157
177
  ]
@@ -162,7 +182,7 @@ Fields:
162
182
  - `statement` — required, ≤2000 chars.
163
183
  - `verifierType` — `"MACHINE"` | `"HUMAN"`.
164
184
  - `checkpointer` — required for MACHINE.
165
- - `referentKind` — **required**, `"EXTERNAL_FACT"` | `"AGENT_CONSTRUCTED_STATE"` | `"PENDING_OUTCOME"` (see "referentKind" above). Your own tests/build/type-check are `AGENT_CONSTRUCTED_STATE`; `EXTERNAL_FACT` is gated (warned at set, 422 at verify) unless the checkpointer truly grounds external; `PENDING_OUTCOME` can't be MACHINE.
185
+ - `referentKind` — optional and advisory; the stored kind is derived from the checkpointer (see "referentKind" above). Only meaningful on a HUMAN criterion (`"EXTERNAL_FACT"` | `"AGENT_CONSTRUCTED_STATE"`).
166
186
  - `evidenceRequired` — optional, default false.
167
187
  - `judgeSteps` — optional, ≤2000 chars; agent-drafted human-judging steps for a HUMAN criterion (see "judgeSteps" above).
168
188
  - `id` — only in `--human` revisions (see below).
@@ -214,9 +234,29 @@ lumo task criteria list LUM-42
214
234
 
215
235
  - **Session start** (bound task): the contract is the highest-priority section in the injection budget — ahead of memory/PR/Slack/Figma/web. If a still-open task has no criteria, the draft reminder is injected instead.
216
236
  - **`lumo session attach`**: prints the contract (or the draft reminder) right after binding.
237
+ - **The reference-class block** rides on the draft reminder at all three of those surfaces, so it appears only when the task has no contract yet — the one moment it can still change what gets written. It is capped at a few lines, sits outside the injection budget, and is skipped silently if the read fails or the workspace has acceptance mode off.
217
238
  - **`lumo task context`**: the `## Acceptance criteria (contract)` section appears after the task description, before memory.
218
239
  - **Review-time gap findings** are appended at the round they surface and show up in the contract automatically — `REVIEW_ADDED` provenance via human review paths; findings a human raises in conversation are transcribed with `--human` + `--cause` (see verify.md "Review-time drift habits").
219
240
 
220
241
  ## After the contract: the verification loop
221
242
 
222
243
  The contract is judged by `lumo verify` — run it before claiming the task is done. See [verify.md](verify.md) for the loop (a workspace-configurable round cap — `verificationMaxRounds`, default 3, shown as `Round N/M` in the output — IN_REVIEW on all-pass, escalation on a last-round fail).
244
+
245
+ ## `lumo criteria audit` — workspace referent-kind analytics
246
+
247
+ ```bash
248
+ lumo criteria audit
249
+ ```
250
+
251
+ `lumo criteria audit` — workspace-level acceptance-criteria analytics. Calls `GET /api/criteria/audit` and prints two things:
252
+
253
+ 1. **Declared-kind distribution** — count of criteria by effective referent kind:
254
+ - `EXTERNAL_FACT` — declared as externally observable (git SHA, CI status, DB row) and the checkpointer invokes real external tooling
255
+ - `AGENT_CONSTRUCTED_STATE` — passes by checking output the agent itself produced
256
+ - `PENDING_OUTCOME` — deferred to post-hoc falsifier
257
+ - `UNVERIFIED_ASSERTION` — a legacy row declared `EXTERNAL_FACT` (before LUM-733 derivation) whose checkpointer does **not** actually invoke external tooling (git/CI/HTTP); reported as-is. New rows can't land here — the kind is derived from the checkpointer at write time (see "referentKind")
258
+ - `UNCLASSIFIED` — legacy rows predating the `referentKind` field (null in DB)
259
+
260
+ 2. **Self-confirming-green headline ratio** — `(AGENT_CONSTRUCTED_STATE + UNVERIFIED_ASSERTION) / classified`. Criteria in these two buckets pass by confirming only the agent's own work, not an independent external state.
261
+
262
+ **When to suggest**: when the user wants to audit how much of the workspace's "green" criteria are self-confirming vs externally anchored; when diagnosing whether acceptance criteria have real external hooks or are circular.
@@ -121,24 +121,26 @@ lumo doc diff cmd_xxx --file docs/live-docs/research-intake-ledger.md
121
121
 
122
122
  The **recovery path for a source-less doc**. When a doc has no stored `sourceMarkdown` — a web HTML-direct edit or revision restore nulled it, or the doc predates source storage — every markdown write path (`--raw`, `--section`, `doc patch`, `doc append --section`, `doc diff`) is locked. This regenerates a valid source by serializing the **stored HTML structure model** back to markdown with a **lossless serializer that round-trips tables/rows/headings** (the default `doc show` render flattens tables, so it was never a safe rebuild base). Only the `sourceMarkdown` column is backfilled; the rendered body is untouched, so the doc reads identically and you just regain the edit base.
123
123
 
124
- | Flag | Type | Notes |
125
- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
126
- | `--allow-shrink` | boolean | Commit even if the rebuilt source re-renders with fewer tables/rows/headings than the stored body (default: 422 reject). |
127
- | `--force` | boolean | Re-derive even when a source already exists (default: 409 protects a byte-faithful human source from a downgrade). |
128
- | `--if-revision <n>` | int | Only apply if the body is still at this revision (from `doc show`). |
124
+ | Flag | Type | Notes |
125
+ | ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
126
+ | `--allow-shrink` | boolean | Commit even if the rebuilt source re-renders with fewer tables/rows/headings than the stored body (default: 422 reject). |
127
+ | `--force` | boolean | Re-derive even when a source already exists. Without it an existing source yields exit 4 + a confirmation envelope whose `confirmCommand` carries `--force --confirm` ([confirmation.md](confirmation.md)). |
128
+ | `--confirm` | boolean | The user approved replacing the existing source; pair it with `--force` as the envelope instructs. |
129
+ | `--if-revision <n>` | int | Only apply if the body is still at this revision (from `doc show`). |
129
130
 
130
- The rebuild is **structure-guarded** (the same guard as `doc update`/`doc patch`): if the serializer would drop any table/row/heading, it is rejected with **422** rather than silently committing a flattened source — `--allow-shrink` is the explicit escape hatch. A doc that already has a source is refused **409** unless `--force`.
131
+ The rebuild is **structure-guarded** (the same guard as `doc update`/`doc patch`): if the serializer would drop any table/row/heading, it is rejected with **422** rather than silently committing a flattened source — `--allow-shrink` is the explicit escape hatch. A doc that already has a source is refused by the server (409); the CLI turns that refusal into a **confirmation envelope** (exit 4, `changes` = the server's reason + what `--force` would replace) so the user sees it before anything is overwritten.
131
132
 
132
133
  ```bash
133
- lumo doc rebuild-source cmd_xxx # restore a source-less doc; --raw works after
134
- lumo doc rebuild-source cmd_xxx --force # re-derive even if a source already exists
134
+ lumo doc rebuild-source cmd_xxx # restore a source-less doc; --raw works after
135
+ lumo doc rebuild-source cmd_xxx # source exists exit 4 + envelope, nothing written
136
+ lumo doc rebuild-source cmd_xxx --force --confirm # re-derive after the user approved the envelope
135
137
  ```
136
138
 
137
139
  ### When to suggest `doc rebuild-source`
138
140
 
139
141
  - A `--raw` / `--section` / `doc patch` / `doc diff` call errored with "no stored markdown source" — rebuild, then retry. This is the first thing to try, not a manual reconstruction.
140
142
  - A table-heavy live doc (e.g. a `docs/live-docs/` registry) lost its source after a web operation and the markdown write path is locked.
141
- - Do **not** run it on a doc that already has a good source unless the user explicitly wants to re-derive it (then pass `--force`) — it replaces the byte-faithful source with a serializer-derived one.
143
+ - Do **not** run it on a doc that already has a good source unless the user explicitly wants to re-derive it (then re-run the envelope's `confirmCommand`, i.e. `--force --confirm`) — it replaces the byte-faithful source with a serializer-derived one.
142
144
 
143
145
  ## Out of scope (CLI v1)
144
146
 
@@ -164,12 +164,13 @@ lumo doc move "Sub-doc" --root
164
164
  - User says "move doc X under Y", "reparent X to root", "promote X to top level".
165
165
  - After `doc create`, if the user realizes the new doc should live elsewhere — suggest `doc move` rather than recreating.
166
166
 
167
- ## `lumo doc delete <doc> --yes` — delete a document
167
+ ## `lumo doc delete <doc> --confirm` — delete a document
168
168
 
169
- Requires `--yes`; no interactive prompt (agent-friendly).
169
+ Deletes the document **and every document nested under it**. Without `--confirm` the CLI looks the doc up and exits **4** with a confirmation envelope (`Will delete document cmd_xxx "Title"` + the nested-docs rule) — nothing is deleted; relay `changes` to the user and re-run `confirmCommand` on approval ([confirmation.md](confirmation.md)). `--yes` is a legacy alias.
170
170
 
171
171
  ```bash
172
- lumo doc delete cmd_xxx --yes
172
+ lumo doc delete cmd_xxx # exit 4 + envelope
173
+ lumo doc delete cmd_xxx --confirm # after the user approved
173
174
  ```
174
175
 
175
176
  ## `lumo doc bind <doc> <task>` / `lumo doc unbind <doc> <task>` — task linkage
@@ -0,0 +1,82 @@
1
+ # Ideas (team-level capture pool)
2
+
3
+ An **idea** is an un-triaged spark parked above the project layer — not yet actionable work. Ideas are team-scoped (no project); the workspace's default team owns them. Ids are **I-prefixed** (`LUM-I42`) so they cannot collide with task ids (`LUM-42`) in the same team namespace.
4
+
5
+ The unprocessed (`CAPTURED`) pool is what the `lumo plan` converter consumes — see [plan-runs.md](plan-runs.md).
6
+
7
+ ## `lumo idea "<statement>" [--context <text>]`
8
+
9
+ Capture an idea into the pool in under 10 seconds. Provenance is grabbed opportunistically and **never blocks the capture**: the current `CLAUDE_CODE_SESSION_ID` (→ `sourceSessionId`) and the session's bound task (→ `sourceTaskId`, null when nothing is bound). Prints `✓ 想法 LUM-I42 已入池`.
10
+
11
+ **When to suggest**: the user has a stray idea / thought / improvement they want to park without derailing the current task ("记一下这个想法", "capture this idea", "add to the backlog of ideas"). Prefer this over `task create` for un-triaged sparks — an idea is above projects and isn't yet actionable work.
12
+
13
+ ```bash
14
+ lumo idea "Add a quick-capture keyboard shortcut" --context "raised in standup"
15
+ ```
16
+
17
+ ## `lumo idea list`
18
+
19
+ Print the pool **newest-first**, one line per idea: the `LUM-I<n>` id, status and statement. Reads `GET /api/ideas`, which returns the **whole** pool (every status), not just the unprocessed slice. Empty pool prints `No ideas.`
20
+
21
+ The same pool is browsable/searchable in web at `/workspace/<slug>/ideas` (sidebar → Ideas), where a `PLANNED` idea links to the plan run that materialised it and the status filter hides `DROPPED` by default.
22
+
23
+ **When to suggest**: the user wants to see what's parked ("看看想法池", "list the ideas"), or is triaging before running `lumo plan`.
24
+
25
+ ```bash
26
+ lumo idea list
27
+ ```
28
+
29
+ ## `lumo idea update <id> --status <captured|developing|planned|dropped>`
30
+
31
+ Move an idea through its lifecycle (LUM-679). `<id>` is the `LUM-I<n>` id (a bare number also resolves); `--status` is case-insensitive.
32
+
33
+ | State | Meaning |
34
+ | ------------ | -------------------------------- |
35
+ | `CAPTURED` | pooled, un-triaged |
36
+ | `DEVELOPING` | in triage / pre-work |
37
+ | `PLANNED` | consumed by an initiative / plan |
38
+ | `DROPPED` | terminal discard |
39
+
40
+ Allowed transitions: `CAPTURED ↔ DEVELOPING`, `DEVELOPING → PLANNED`, and **any non-terminal → DROPPED**. Nothing transitions out of `DROPPED`. `CAPTURED → PLANNED` is **not** a manual move — only the converter's materialisation lands an idea in `PLANNED`. An illegal move is rejected with a clear error (400); an unknown id → 404.
41
+
42
+ **When to suggest**: the user wants to triage by hand — start pre-work ("开始预研这个想法" → `developing`) or discard one ("废弃/丢掉这个想法" → `dropped`). The same control lives on the Idea detail page in web.
43
+
44
+ ```bash
45
+ lumo idea update LUM-I42 --status developing
46
+ lumo idea update LUM-I42 --status dropped
47
+ ```
48
+
49
+ ## Evidence on an idea — `slack` / `web` / `figma`
50
+
51
+ `lumo idea slack add|show|rm`, `lumo idea web add|show|rm`, `lumo idea figma add|list|rm|refresh|context` (LUM-681) attach and inspect supporting evidence, mirroring the `task slack/web/figma` source-card commands but hitting `/api/ideas/:id/...`. `<idea>` is the `LUM-I<n>` id.
52
+
53
+ `show` / `context` are **Tier-2 retrieval** (stored snapshot / fetched body / cached design metadata — no live re-fetch) and stamp the disclosure funnel like their task-side counterparts. `figma refresh` re-fetches metadata for every link on the idea.
54
+
55
+ **When to suggest**: the user wants to attach evidence (a Slack discussion, a spec link, a Figma mock) to an idea **before** it goes through `lumo plan` — the converter carries that evidence forward into the resulting task/initiative. Prefer attaching to the idea over waiting until after conversion.
56
+
57
+ ```bash
58
+ lumo idea web add LUM-I42 https://example.com/spec
59
+ lumo idea web show LUM-I42 wl_1
60
+ lumo idea web rm LUM-I42 wl_1
61
+ lumo idea slack add LUM-I42 https://myteam.slack.com/archives/C1/p123
62
+ lumo idea slack show LUM-I42 ctx_1
63
+ lumo idea slack rm LUM-I42 ctx_1
64
+ lumo idea figma add LUM-I42 https://www.figma.com/file/abc/Mock
65
+ lumo idea figma list LUM-I42
66
+ lumo idea figma context LUM-I42 cfl_1
67
+ lumo idea figma refresh LUM-I42
68
+ lumo idea figma rm LUM-I42 cfl_1
69
+ ```
70
+
71
+ ## Comments — `lumo idea comment` / `lumo idea comments list`
72
+
73
+ `lumo idea comment <id> <body>` posts a comment (LUM-680). `<id>` is the `LUM-I<n>` id (a bare number or a cuid also resolves); the body is plain text — quote it to pass spaces/newlines. Ideas reuse the task `Comment` model via a polymorphic `ideaId`; the thread is **flat** (no replies). Posting also records a `COMMENT_ADDED` entry on the idea's activity timeline.
74
+
75
+ `lumo idea comments list <id> [--full]` prints the thread oldest-first, capped to the output budget like `task comments list`; `--full` prints every comment. Empty thread → `(no comments)`.
76
+
77
+ **When to suggest**: the user wants to discuss or annotate a parked idea ("给这个想法加条评论"), or review its discussion/history ("看看这个想法的评论/活动"). For the **activity timeline** (status changes, statement edits, materialisation) there is no CLI reader — it renders on the Idea detail slide-over in web.
78
+
79
+ ```bash
80
+ lumo idea comment LUM-I42 "Let's scope this for next sprint"
81
+ lumo idea comments list LUM-I42
82
+ ```
@@ -0,0 +1,28 @@
1
+ # Initiatives (team-level, `LUM-INIT-<n>`)
2
+
3
+ An **Initiative** is a team-level strategic goal that tasks roll up to. Two origins land in the same list:
4
+
5
+ - **Direct** — `lumo initiative create`, no plan run required (`planRunId = null`, status `ACTIVE`).
6
+ - **Materialised** — produced by the `lumo plan` converter's gate C, carrying its lineage (see [plan-runs.md](plan-runs.md)).
7
+
8
+ ## `lumo initiative create "<goal>" [--assumption <text>]`
9
+
10
+ Create an Initiative directly. Prints the `LUM-INIT-<n>` id. `--assumption` records the bet (赌注旁注) behind it — the thing that, if false, makes the initiative the wrong call. A blank goal is rejected (400).
11
+
12
+ **When to suggest**: the user wants to stand up a strategic initiative directly — "建一个 initiative", "create an initiative", "开一个举措" — without running the converter.
13
+
14
+ ```bash
15
+ lumo initiative create "Ship the initiatives browse surface" --assumption "teams curate initiatives directly"
16
+ ```
17
+
18
+ ## `lumo initiative list`
19
+
20
+ Print the team's initiatives newest-first, one line each: the `LUM-INIT-<n>` id, status (`ACTIVE` | `DONE` | `DROPPED`) and goal.
21
+
22
+ Browsable in web at `/workspace/<slug>/initiatives` (sidebar → Initiatives), where each links to its lineage — the ideas it consumed and the tasks attached to it.
23
+
24
+ **When to suggest**: the user wants to see the team's initiatives ("看看 initiatives", "list the initiatives").
25
+
26
+ ```bash
27
+ lumo initiative list
28
+ ```
@@ -32,7 +32,7 @@ lumo project memory add [<project>] --category convention --rule "..." --applies
32
32
  # Single-memory ops (memoryId from `... memory list` column 1)
33
33
  lumo memory show <memoryId> # show one memory's full card by id
34
34
  lumo memory promote <memoryId> # TASK → PROJECT
35
- lumo memory rm <memoryId> --yes # hard delete
35
+ lumo memory rm <memoryId> --confirm # hard delete (without --confirm: exit 4 + envelope)
36
36
 
37
37
  # Downsync team memory into the local Claude Code memory store
38
38
  lumo memory sync # write team/<id>.md + a managed MEMORY.md block
@@ -68,9 +68,11 @@ lumo project memory add lumo --category procedural --workflow "Regenerate the CL
68
68
  # Curate
69
69
  lumo memory show cmpi19iqabc123
70
70
  lumo memory promote cmpi19iqabc123
71
- lumo memory rm cmpi19iqabc123 --yes
71
+ lumo memory rm cmpi19iqabc123 --confirm
72
72
  ```
73
73
 
74
+ `memory rm` is gated by the confirmation protocol ([confirmation.md](confirmation.md)): without `--confirm` it fetches the card and exits **4** with an envelope (`Will hard-delete memory <id> [TRAP]` · `Content: <first line>` · no undo) and deletes nothing. Show that to the user first; `--yes` is a legacy alias of `--confirm`.
75
+
74
76
  ### `lumo memory show <id>` (progressive disclosure)
75
77
 
76
78
  Fetches one memory's full card by id from the server and prints its category tag
@@ -194,10 +194,11 @@ lumo milestone criteria verdict "Q3 Launch" cmexit0002 --unmet --note "read mode
194
194
 
195
195
  ### `lumo milestone delete <identifier>` — delete a milestone
196
196
 
197
- Requires `--yes`. No interactive prompt CLI is agent-friendly. Tasks under the milestone keep their data; their `milestoneId` is cleared.
197
+ Gated by the confirmation protocol ([confirmation.md](confirmation.md)): without `--confirm` the CLI exits **4** with an envelope (`Will delete milestone "Q3 Launch"` · `12 tasks under it keep their data; only milestoneId is cleared`) and deletes nothing — relay it to the user and re-run `confirmCommand` on approval. `--yes` is a legacy alias. Tasks under the milestone keep their data; their `milestoneId` is cleared.
198
198
 
199
199
  ```bash
200
- lumo milestone delete "Q3 Launch" --yes
200
+ lumo milestone delete "Q3 Launch" # exit 4 + envelope
201
+ lumo milestone delete "Q3 Launch" --confirm # after the user approved
201
202
  ```
202
203
 
203
204
  ### `lumo milestone archive <identifier>` — soft-archive a milestone
@@ -14,7 +14,7 @@ There is **no `SATISFIED` / `PASS`**. "N sprints and nobody touched it" is the _
14
14
  ## Collection (where signals come from)
15
15
 
16
16
  - **Automatic** — a DONE task reopened (the lineage `REWORKED` transition) is folded into the well as a `REOPENED` signal. No action needed; it happens server-side.
17
- - **Manual** — a human who observed reality reject a delivery records it with `lumo outcome record`. The `--note` is mandatory: it is the observed referent, frozen as evidence.
17
+ - **Git-derived** — a revert (or a content reversal) of the delivery's commits landing on the default branch is recorded from the push webhook as `REVERTED` / `DOWNSTREAM_REDIRECT` (LUM-607). No manual recording path exists any more: the former `lumo outcome record` command was removed in LUM-733 (it was never used 0 MANUAL signals all-time); CI-derived signals (`CI_REGRESSION` / `ROLLED_BACK`) are a follow-up.
18
18
 
19
19
  ## `lumo outcome show <task>`
20
20
 
@@ -26,18 +26,6 @@ lumo outcome show LUM-42
26
26
 
27
27
  An empty well prints `INCONCLUSIVE` with the reminder that silence is not a pass. A non-empty well prints `REJECTED` and lists each signal (date, kind, source, note).
28
28
 
29
- ## `lumo outcome record <task> --note "<what reality did>" [--kind <kind>]`
30
-
31
- Record one human-observed post-hoc rejection. Append-only — every call inserts a new signal; nothing is ever mutated or cleared.
32
-
33
- ```bash
34
- lumo outcome record LUM-42 --note "reverted in #812 after a prod incident" --kind reverted
35
- lumo outcome record LUM-42 --note "downstream rewrote the API shape this task introduced" --kind downstream_redirect
36
- ```
37
-
38
- - `--kind` (case-insensitive, default `manual`): `reverted | rolled_back | ci_regression | downstream_redirect | bypassed | manual`. `reopened` is **not** a manual kind — it is owned by the automatic lineage fold.
39
- - `--occurred-at <iso>` — when the event actually happened (defaults to now).
40
-
41
29
  ## `lumo outcome rate [--min N] [--json]`
42
30
 
43
31
  The workspace-level **trust × post-hoc-fate** join (LUM-603, LUM-606). For every delivery that has a frozen forecast snapshot, it buckets the delivery by its **delivery-time verification friction** — two raw counts (`verificationRounds`, `sendBackCount`) frozen at delivery from the append-only `VerificationRun` log, cut at `capturedAt`, then bucketed value-neutrally into `no-verification` / `single-round` / `multi-round-or-sendback` — and reports each bucket's post-hoc **REJECTED** rate from the well. The friction axis replaced the original sample-size forecast-confidence axis (LUM-606), which saturated: every mature-project delivery landed in `high`, so `high`-vs-`low` could never compare. The question it answers once data is sufficient: _do deliveries that took more verification friction get rejected by reality more (fragility) or less (scrutiny) often?_ The bucket names carry **no** good/bad direction — the correlation, not the label, decides.
@@ -59,7 +47,6 @@ This is the falsifier discipline applied at the **query layer** — it refuses t
59
47
 
60
48
  ## When to suggest
61
49
 
62
- - A teammate says a shipped task **was reverted / rolled back / broke prod / got redone / was bypassed** — record it with `lumo outcome record` so the well carries reality's verdict.
63
50
  - Auditing whether a "done" task actually held up — `lumo outcome show <task>` reads the well.
64
51
  - Asking whether **verification friction predicts post-hoc fate** (do harder-to-verify deliveries fail more, or less?) — `lumo outcome rate`. Expect `inconclusive` until the well fills; it will never print a correlation the sample can't support.
65
52
  - **Never** use it to mark something good: the well has no positive verdict by design. To assert a delivery met its contract, that is the acceptance loop (`lumo verify` / `lumo task status`), not the well.
@@ -0,0 +1,32 @@
1
+ # Plan runs (design-thinking 转换器)
2
+
3
+ A **plan run** turns the team's captured idea pool + the current priority declaration into an executable plan, through a 3-gate recoverable state machine: **聚类 → 对齐 → 成计划**.
4
+
5
+ The CLI only **triggers and reports**. All editing and gate confirmation happen in **web** — the CLI hands off a deep-link.
6
+
7
+ Inputs come from [ideas.md](ideas.md) (the `CAPTURED` pool) and [priority.md](priority.md) (the current declaration). Materialisation produces tasks plus, when the plan calls for one, an Initiative — see [initiatives.md](initiatives.md).
8
+
9
+ ## `lumo plan [--abandon-active]`
10
+
11
+ Start a converter run. Freezes the input snapshot at start and enforces **one active run per team**: if a run is already active it refuses and points to `lumo plan status`. `--abandon-active` abandons the prior run first, then starts fresh.
12
+
13
+ On success it prints (and opens) the **gate-A** web deep-link, `/workspace/<slug>/plan/<runId>`.
14
+
15
+ Invoked bare (`lumo plan`) it starts a run; `lumo plan --abandon-active` clears a stuck one first. The command is a parent with its own action — `status` below is a subcommand added on top of it, not a required one.
16
+
17
+ **When to suggest**: the user wants to turn the parked idea pool into a plan — "跑一下转换器", "start a planning run", "把想法变成计划".
18
+
19
+ ```bash
20
+ lumo plan
21
+ lumo plan --abandon-active
22
+ ```
23
+
24
+ ## `lumo plan status`
25
+
26
+ Print the active run's current stage — either the working segment or the open `*_READY` gate — plus the deep-link to act on its next gate. With no active run, prompts to run `lumo plan`.
27
+
28
+ **When to suggest**: the user asks where an in-flight run stands ("plan 到哪一步了", "plan status"). The gate work itself is web-only.
29
+
30
+ ```bash
31
+ lumo plan status
32
+ ```
@@ -36,7 +36,7 @@ When the session is bound, session-start may inject a **"🆕 Review needed: pro
36
36
 
37
37
  #### When to suggest
38
38
 
39
- Briefly sanity-check each listed memory against the codebase/context. If one is wrong or over-generalized, remove it with `lumo memory rm <id> --yes` (ideally confirm with the user first). If they all look right, ignore the section and continue.
39
+ Briefly sanity-check each listed memory against the codebase/context. If one is wrong or over-generalized, remove it with `lumo memory rm <id>` it exits 4 with a confirmation envelope; show it to the user and re-run with `--confirm` only on their approval ([confirmation.md](confirmation.md)). If they all look right, ignore the section and continue.
40
40
 
41
41
  ### Blocker alert injected at `session attach` / session-start
42
42
 
@@ -73,7 +73,7 @@ Detected 3 candidate dependencies awaiting confirmation: run `lumo task deps lis
73
73
  Watch for EITHER the `## ⚠ Dependency alerts` header (form A) OR the standalone hint line (form B).
74
74
 
75
75
  - `lumo task deps list <LUM-N>` — inspect the full edge list (run for any candidate hint, form A or B; confirm real SUGGESTED edges, dismiss false positives — unreviewed edges mean repeated hints every session).
76
- - `lumo task deps rm <LUM-N> <edge> --yes` — drop a manually-added, now-obsolete edge.
76
+ - `lumo task deps rm <LUM-N> <edge> --confirm` — drop a manually-added, now-obsolete edge (exit 4 + envelope without `--confirm`).
77
77
  - `lumo task deps dismiss <LUM-N> <edge>` — dismiss a false positive from detection.
78
78
  - Form A live blockers: evaluate whether to wait — overlapping work (same files, same API surface) risks rework; read the blocker's status and open-PR note before deciding.
79
79
  - Do **not** blindly start work on a task whose live blocker is still IN_PROGRESS or IN_REVIEW unless the user explicitly decides to proceed in parallel.
@@ -91,7 +91,7 @@ What it does:
91
91
  - Reads `CLAUDE_CODE_SESSION_ID` from the environment (Claude Code sets it automatically); errors out if unset — must run from inside a Claude Code session.
92
92
  - Calls `POST /api/sessions/<session_id>/bind-task`, which sets the Session row's `taskId` and re-tags previously-untagged HookEvent rows in this session.
93
93
  - The binding lives entirely on the server (`Session.taskId`); subsequent hooks read it back via the session row. The CLI keeps no local sentinel.
94
- - Prints the task's **acceptance contract** (`## Acceptance criteria (contract)`) right after the bind confirmation — or, when a still-open task has none, the draft reminder to draft 3–7 criteria before the first line of code (see [criteria.md](criteria.md)). The same section is auto-injected at session start when already bound (highest priority in the injection budget, ahead of memory).
94
+ - Prints the task's **acceptance contract** (`## Acceptance criteria (contract)`) right after the bind confirmation — or, when a still-open task has none, the draft reminder to draft 3–7 criteria before the first line of code, followed by the `### Reference class (outside view)` block when history supports one (see [criteria.md](criteria.md)). The same section is auto-injected at session start when already bound (highest priority in the injection budget, ahead of memory).
95
95
 
96
96
  After attaching, always run `lumo task context <identifier>` to load the task background.
97
97
 
@@ -134,7 +134,7 @@ lumo session attach --steward cmxyz123... # by milestone id
134
134
  - **Multiple stewards per milestone are allowed** (acceptance is multi-round by nature); sessions don't conflict.
135
135
  - **Prior-milestone learnings injected at attach (LUM-647):** the attach prints a `## Prior-milestone learnings (this project)` section — the **MILESTONE-scope** memories distilled from this project's earlier milestone-close retros (a cross-milestone learning unit), wrapped in the `<untrusted-team-memory>` boundary. Empty when the project has no prior distilled learnings; the current milestone's own rows are excluded. A resumed steward session re-gets it via the session-start hook. These memories are written automatically when a milestone closes and its retro is generated — there is no manual command to author them.
136
136
 
137
- **Allowed (governance — pass through unchanged, with the session recorded as provenance):** `task create` / `task update`, `task criteria set` (incl. `--human`), `task deps confirm/dismiss`, `verdict --fail` (the send-back rows carry `sourceSessionId`), `milestone add/remove`, and **all read operations**.
137
+ **Allowed (governance — pass through unchanged, with the session recorded as provenance):** `task create` / `task update`, `task criteria set` (incl. `--human`), `task deps confirm/dismiss`, `milestone add/remove`, and **all read operations**.
138
138
 
139
139
  **Blocked (implementation — first layer, API gate):**
140
140
 
@@ -176,7 +176,9 @@ The old end-of-session command was **removed**. The three passes it ran interact
176
176
  - confidently-unused → `used=false`
177
177
  - genuinely-uncertain edges stay `null` (honest "not voted", not "unused")
178
178
 
179
- Already-voted sessions are skipped; a cron backstop drains any backlog. **Why:** upgrades the flywheel signal from "co-loaded" (constant) to "actually used" (discriminative); `task context` then prefers each fragment's usage-based merge rate, falling back to the presence rate when usage samples are thin.
179
+ Already-voted sessions are skipped; a cron backstop drains any backlog. **Why:** upgrades the flywheel signal from "co-loaded" (constant) to "actually used" (discriminative). `task context` then reports each fragment's **judged-used track record** — of the N tasks it appeared in, X were judged to have actually used it. That is a **lower bound** (never-audited appearances are excluded from the proven/retire calls), and it **replaced the retired merge-rate signal** (RFC LUM-535).
180
+
181
+ > Don't confuse this with the used-vs-base **merge rate** still reported by `lumo task lineage --signal` ([task-context.md](task-context.md)) — that is a different, live metric for workspace signal-health, not the retired fragment-usefulness one.
180
182
 
181
183
  **3. Blocked-tag automation (server-side).** When a session crosses the same-tool failure threshold (**≥ 3** same-type failures, aggregated from `POST_TOOL_USE_FAILURE` grouped by tool name + `STOP_FAILURE` turn-level failures), the server **auto-applies the shared `blocked` tag** to the bound task. This inverts the old manual gate — no prompt, no human in the loop — and is safe via three safeguards:
182
184
 
@@ -42,15 +42,12 @@ When to suggest: user says "create a sprint", "new sprint", "start a new iterati
42
42
 
43
43
  `<identifier>` accepts a sprint number (e.g. `3`) or a UUID. `--team` is required when using a number in a multi-team workspace.
44
44
 
45
- Output: key:value header (number, name, status, dates, team), then a `Progress:` line, then a **`Health:` line** with the sprint's risk level (`HEALTHY` / `WATCH` / `AT-RISK`), then a task table listing every task in the sprint.
45
+ Output: key:value header (number, name, status, dates, team), then a `Progress:` line, then a `Blockers:` section, then a task table listing every task in the sprint.
46
46
 
47
- The risk level reuses the same engine as project/workspace stats, fed the sprint's task set (thresholds come from the workspace risk config sprints have no per-sprint overrides). When the engine flags reasons they print as `- <detail>` lines under `Health:`, and a `Blockers:` section lists the top offenders per category (`Overdue` / `Stalled` / `Agent fail` / `Stale PRs`). A healthy sprint with no blockers shows just the `Health:` line.
47
+ `Blockers:` lists the top offenders per category (`Overdue` / `Stalled` / `Agent fail` / `Stale PRs`) a task counts as stalled after 7 days untouched, a PR as stale after 3 days awaiting review. A sprint with nothing in any category prints no `Blockers:` section at all. (There is no risk score or `Health:` line LUM-709 removed the risk-assessment layer.)
48
48
 
49
49
  ```
50
50
  Progress: 4 / 10
51
- Health: AT-RISK
52
- - 4/10 tasks overdue (40%)
53
- - 3 tasks with no progress in 7 days
54
51
  Blockers:
55
52
  Overdue: LUM-1 Fix login, LUM-8 Wire API
56
53
  Stalled: LUM-5 Add tests
@@ -63,7 +60,7 @@ lumo sprint show 3 --team backend
63
60
  lumo sprint show 11111111-2222-3333-4444-555555555555
64
61
  ```
65
62
 
66
- When to suggest: user asks "what's in sprint 3", "show me the current sprint", "what tasks are in this sprint", "is this sprint at risk", "sprint health".
63
+ When to suggest: user asks "what's in sprint 3", "show me the current sprint", "what tasks are in this sprint", "what's blocking this sprint".
67
64
 
68
65
  ### `lumo sprint update <identifier> [flags]` — patch a sprint
69
66
 
@@ -83,12 +80,13 @@ lumo sprint update 3 --end 2026-06-21
83
80
 
84
81
  When to suggest: user wants to rename a sprint, extend dates, or fix sprint metadata.
85
82
 
86
- ### `lumo sprint delete <identifier> --yes` — delete a sprint (DRAFT only)
83
+ ### `lumo sprint delete <identifier> --confirm` — delete a sprint (DRAFT only)
87
84
 
88
- Requires `--yes`; no interactive prompt (agent-friendly). Server rejects with an error if the sprint is ACTIVE or CLOSED.
85
+ Without `--confirm` the CLI exits **4** with a confirmation envelope (`Will delete sprint #3 "Sprint 3"` · `N tasks under it keep their data; only sprintId is cleared`) and deletes nothing — relay it to the user, re-run `confirmCommand` on approval ([confirmation.md](confirmation.md)). `--yes` is a legacy alias. Server rejects with an error if the sprint is ACTIVE or CLOSED.
89
86
 
90
87
  ```bash
91
- lumo sprint delete 3 --yes
88
+ lumo sprint delete 3 # exit 4 + envelope
89
+ lumo sprint delete 3 --confirm # after the user approved
92
90
  ```
93
91
 
94
92
  When to suggest: user wants to remove a draft sprint that was created by mistake.
@@ -107,18 +105,21 @@ When to suggest: user says "start the sprint", "kick off sprint 3", "activate sp
107
105
 
108
106
  Handles unfinished tasks based on flags. Without flags: closes only if all tasks are done; otherwise prints a list of unfinished tasks and refuses.
109
107
 
110
- | Flag | Type | Notes |
111
- | --------------- | ------- | -------------------------------------------------------------------------------- |
112
- | `--move-all` | boolean | Move all unfinished tasks to the next sprint. Requires `--yes`. |
113
- | `--backlog-all` | boolean | Remove all unfinished tasks from the sprint (send to backlog). Requires `--yes`. |
114
- | `--yes` | boolean | Required when `--move-all` or `--backlog-all` is given. |
108
+ | Flag | Type | Notes |
109
+ | --------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
110
+ | `--move-all` | boolean | Move all unfinished tasks to the next sprint. Gated by `--confirm`. |
111
+ | `--backlog-all` | boolean | Remove all unfinished tasks from the sprint (send to backlog). Gated by `--confirm`. |
112
+ | `--confirm` | boolean | The user approved the envelope. Without it a mode flag exits 4 with a confirmation envelope listing every task that would move (`--yes` is a legacy alias). |
115
113
 
116
114
  ```bash
117
- lumo sprint close 3 # fails if unfinished tasks exist
118
- lumo sprint close 3 --move-all --yes # move unfinished to next sprint
119
- lumo sprint close 3 --backlog-all --yes # send unfinished to backlog
115
+ lumo sprint close 3 # fails (exit 1) if unfinished tasks exist — pick a mode
116
+ lumo sprint close 3 --move-all # exit 4 + envelope: "2 unfinished tasks move to the next sprint: LUM-3, LUM-4"
117
+ lumo sprint close 3 --move-all --confirm # move unfinished to next sprint (after the user approved)
118
+ lumo sprint close 3 --backlog-all --confirm # send unfinished to backlog
120
119
  ```
121
120
 
121
+ See [confirmation.md](confirmation.md) for the envelope shape and the relay rules.
122
+
122
123
  When to suggest: user says "close the sprint", "end sprint 3", "wrap up the sprint". If they haven't decided what to do with unfinished tasks, ask before adding `--move-all` or `--backlog-all`.
123
124
 
124
125
  ### `lumo sprint summary <identifier> [--retry]` — fetch AI-generated sprint retro
@@ -13,7 +13,7 @@ lumo task context LUM-42
13
13
  The command prints a markdown document to stdout with these sections, in order:
14
14
 
15
15
  1. **Task header** — identifier, title, status, description.
16
- 2. **`## Acceptance criteria (contract)`** — shown right after the header. Each line `[MACHINE|HUMAN] statement`, with a `↳ check:` line for MACHINE checkpointers; HUMAN_EDIT / REVIEW_ADDED provenance tagged inline. A still-open task with none shows a draft reminder instead — draft 3–7 criteria **before writing code** (see [criteria.md](criteria.md)).
16
+ 2. **`## Acceptance criteria (contract)`** — shown right after the header. Each line `[MACHINE|HUMAN] statement`, with a `↳ check:` line for MACHINE checkpointers; HUMAN_EDIT / REVIEW_ADDED provenance tagged inline. A still-open task with none shows a draft reminder instead — draft 3–7 criteria **before writing code** — followed by a `### Reference class (outside view)` block giving the failure modes of similar delivered tasks, to draft against rather than to copy (see [criteria.md](criteria.md)).
17
17
  3. **Memory section** — cross-session learnings; trusted background context that persists, so you avoid re-learning decisions/constraints.
18
18
  4. **Inline source cards** — Slack / web / Figma / artifacts / documents / comments / Pull Requests (see "Context Retrieval" below).
19
19
  5. **`## PR review todos`** — mirrored PR review comments as a checkbox todo list. Each line-level comment shows `` `file:line` `` + reviewer's ask + GitHub comment link; each `changes_requested` review summary shows "🛑 Changes requested (whole PR)". Present only when the task's PR(s) have review comments. Each unchecked box is a TODO: resolve it, then reply on the PR (a Lumo comment mirrors back to GitHub).
@@ -82,12 +82,13 @@ lumo task deps dismiss LUM-42 e5f6a7b8
82
82
 
83
83
  Use `dismiss` for false positives. Use `rm` only when you want the pair eligible for re-detection again.
84
84
 
85
- ## `lumo task deps rm <LUM-N> <edge> --yes` — delete an edge
85
+ ## `lumo task deps rm <LUM-N> <edge> --confirm` — delete an edge
86
86
 
87
- Hard-deletes the edge row. **Requires `--yes`** the CLI refuses without it (no interactive prompt exists).
87
+ Hard-deletes the edge row. Without `--confirm` it resolves the edge, then exits **4** with a confirmation envelope describing it (`Will delete dependency edge [a1b2c3d4] from LUM-42: blocked by LUM-9 "…" (CONFIRMED, manual)`) and sends nothing — relay `changes` to the user and re-run the envelope's `confirmCommand` on approval (see [confirmation.md](confirmation.md)). `--yes` is a legacy alias of `--confirm`.
88
88
 
89
89
  ```bash
90
- lumo task deps rm LUM-42 a1b2c3d4 --yes
90
+ lumo task deps rm LUM-42 a1b2c3d4 # exit 4 + envelope, nothing deleted
91
+ lumo task deps rm LUM-42 a1b2c3d4 --confirm # after the user approved
91
92
  # Removed [a1b2c3d4] from LUM-42
92
93
  ```
93
94