@lumoai/cli 1.29.0 → 1.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,157 @@
1
+ # Sprint Management
2
+
3
+ ## Sprint Management
4
+
5
+ ### `lumo sprint list [flags]` — list sprints in a team
6
+
7
+ Prints fixed-width rows: `<NUMBER> <STATUS> <start> <end> <name>`, sorted newest-first (server sort).
8
+
9
+ | Flag | Type | Notes |
10
+ | ---------------------- | ------- | ----------------------------------------------------- |
11
+ | `--team <ref>` | string | Team name or slug. Required in multi-team workspaces. |
12
+ | `-s, --status <value>` | enum | `draft \| active \| closed`. |
13
+ | `-n, --limit <count>` | integer | Cap output to the first N rows. |
14
+
15
+ ```bash
16
+ lumo sprint list
17
+ lumo sprint list --status active
18
+ lumo sprint list --team backend --limit 5
19
+ ```
20
+
21
+ When to suggest: user asks "what sprints do we have", "which sprint is active", "list sprints", "show me the current sprint", "active sprints".
22
+
23
+ ### `lumo sprint create [flags]` — create a sprint
24
+
25
+ | Flag | Type | Notes |
26
+ | ---------------- | ------ | ----------------------------------------------------- |
27
+ | `--team <ref>` | string | Team name or slug. Required in multi-team workspaces. |
28
+ | `--start <date>` | string | **Required.** YYYY-MM-DD. |
29
+ | `--end <date>` | string | **Required.** YYYY-MM-DD. |
30
+ | `-n, --name <>` | string | Optional. Server fills a default name when omitted. |
31
+
32
+ ```bash
33
+ lumo sprint create --start 2026-06-01 --end 2026-06-14
34
+ lumo sprint create --name "Sprint 4" --start 2026-06-01 --end 2026-06-14 --team backend
35
+ ```
36
+
37
+ On success: `Created sprint #<number> "<name>" <id>`.
38
+
39
+ When to suggest: user says "create a sprint", "new sprint", "start a new iteration".
40
+
41
+ ### `lumo sprint show <identifier> [--team <ref>]` — show sprint detail + task table
42
+
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
+
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.
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.
48
+
49
+ ```
50
+ Progress: 4 / 10
51
+ Health: AT-RISK
52
+ - 4/10 tasks overdue (40%)
53
+ - 3 tasks with no progress in 7 days
54
+ Blockers:
55
+ Overdue: LUM-1 Fix login, LUM-8 Wire API
56
+ Stalled: LUM-5 Add tests
57
+ Stale PRs: #12, #15
58
+ ```
59
+
60
+ ```bash
61
+ lumo sprint show 3
62
+ lumo sprint show 3 --team backend
63
+ lumo sprint show 11111111-2222-3333-4444-555555555555
64
+ ```
65
+
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".
67
+
68
+ ### `lumo sprint update <identifier> [flags]` — patch a sprint
69
+
70
+ Updates sprint metadata. At least one flag required. **No `--status` flag** — use `lumo sprint start` / `lumo sprint close` to transition status.
71
+
72
+ | Flag | Type | Notes |
73
+ | ---------------- | ------ | --------------------------------------------------------------- |
74
+ | `--team <ref>` | string | Required when identifier is a number in a multi-team workspace. |
75
+ | `-n, --name <>` | string | New name. Cannot be empty. |
76
+ | `--start <date>` | string | YYYY-MM-DD. `--start ""` clears. |
77
+ | `--end <date>` | string | YYYY-MM-DD. `--end ""` clears. |
78
+
79
+ ```bash
80
+ lumo sprint update 3 --name "Sprint 4 (extended)"
81
+ lumo sprint update 3 --end 2026-06-21
82
+ ```
83
+
84
+ When to suggest: user wants to rename a sprint, extend dates, or fix sprint metadata.
85
+
86
+ ### `lumo sprint delete <identifier> --yes` — delete a sprint (DRAFT only)
87
+
88
+ Requires `--yes`; no interactive prompt (agent-friendly). Server rejects with an error if the sprint is ACTIVE or CLOSED.
89
+
90
+ ```bash
91
+ lumo sprint delete 3 --yes
92
+ ```
93
+
94
+ When to suggest: user wants to remove a draft sprint that was created by mistake.
95
+
96
+ ### `lumo sprint start <identifier>` — transition DRAFT → ACTIVE
97
+
98
+ No additional flags. Fails if the sprint is already ACTIVE or CLOSED.
99
+
100
+ ```bash
101
+ lumo sprint start 3
102
+ ```
103
+
104
+ When to suggest: user says "start the sprint", "kick off sprint 3", "activate sprint".
105
+
106
+ ### `lumo sprint close <identifier> [flags]` — transition ACTIVE → CLOSED
107
+
108
+ 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
+
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. |
115
+
116
+ ```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
120
+ ```
121
+
122
+ 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
+ ### `lumo sprint summary <identifier> [--retry]` — fetch AI-generated sprint retro
125
+
126
+ Prints the AI-generated retrospective summary for the sprint. A 404 response means no summary has been generated yet ("no summary yet").
127
+
128
+ | Flag | Type | Notes |
129
+ | --------- | ------- | ------------------------------------------------- |
130
+ | `--retry` | boolean | Queue a regeneration (async, server returns 202). |
131
+
132
+ ```bash
133
+ lumo sprint summary 3
134
+ lumo sprint summary 3 --retry
135
+ ```
136
+
137
+ When to suggest: user asks "summarize the sprint", "sprint retro", "give me a summary of sprint 3".
138
+
139
+ ### `lumo sprint add <identifier> <task>` — bind a task to a sprint
140
+
141
+ Adds `<task>` (e.g. `LUM-48`) to the sprint. Same-team check applies — the task's team must match the sprint's team.
142
+
143
+ ```bash
144
+ lumo sprint add 3 LUM-48
145
+ ```
146
+
147
+ When to suggest: user says "add LUM-48 to sprint 3", "put this task in the sprint".
148
+
149
+ ### `lumo sprint remove <identifier> <task>` — unbind a task from a sprint
150
+
151
+ Removes `<task>` from the sprint. Idempotent — if the task is not in the sprint, the server returns success.
152
+
153
+ ```bash
154
+ lumo sprint remove 3 LUM-48
155
+ ```
156
+
157
+ When to suggest: user says "remove LUM-48 from the sprint", "take this task out of sprint 3", "move task to backlog".
@@ -0,0 +1,136 @@
1
+ # Task Context Loading & Context Retrieval
2
+
3
+ ## Task Context Loading
4
+
5
+ When the user mentions a task identifier or asks for task background, load the context:
6
+
7
+ ```bash
8
+ lumo task context <identifier>
9
+ ```
10
+
11
+ Example: `lumo task context LUM-42`
12
+
13
+ ### Reading the output
14
+
15
+ The command prints a markdown document to stdout containing:
16
+
17
+ 1. **Task header** — identifier, title, status, description
18
+ 2. **Acceptance criteria (contract)** — the task's acceptance criteria (LUM-342), shown right after the header as the `## Acceptance criteria (contract)` section. Each line: `[MACHINE|HUMAN] statement` with a `↳ check:` line for MACHINE checkpointers; HUMAN_EDIT / REVIEW_ADDED provenance is tagged inline. If a still-open task has none, a draft reminder appears instead — draft 3–7 criteria **before writing code** (see [criteria.md](criteria.md))
19
+ 3. **Memory section** — cross-session learnings accumulated over prior sessions; treat as trusted background context
20
+ 4. **Inline source cards** — Slack / web / Figma / artifacts / documents / comments / Pull Requests (see "Context Retrieval" below)
21
+ 5. **PR review todos** — mirrored PR review comments as a checkbox todo list under the `## PR review todos` header: each line-level reviewer comment (shown as `` `file:line` `` + the reviewer's ask + a link to the GitHub comment) and each `changes_requested` review summary (shown as "🛑 Changes requested (whole PR)"). Present only when the task's PR(s) have review comments. This same block is **auto-injected at session start** (alongside the memory section) when the session is bound to a task — so reviewer asks surface without re-running `task context`.
22
+ - The **inline source cards** (Slack / web / Figma / PR) are likewise **auto-injected at session start** when the session is bound, under a single global token budget shared with the memory section (priority: criteria > memory > PR > Slack > Figma > web). Cards that don't fit the budget are degraded to a one-line manifest carrying just the title and its `lumo task … show` retrieval command — so you still know they exist and can pull the full content on demand.
23
+ 6. **Previous sessions** — ordered newest-first, each with:
24
+ - A headline summary of what was done
25
+ - Unresolved items (carry-over TODOs from that session)
26
+ 7. **Flywheel signal · historical merge contribution** — appended at the very end as the `## Flywheel signal · historical merge contribution` section. For each context fragment with enough history, a one-line historical merge-contribution signal (e.g. `appeared in 5 resolved tasks · 4 merged (80%)`), computed from accumulated lineage edges. Denominator = distinct tasks where the fragment appeared with a resolved (non-UNKNOWN) outcome; only fragments with ≥3 such tasks are shown (cold-start gate), so the block is often absent early on. This is **historical correlation, not causation** — don't read it as a prediction.
27
+
28
+ ### How to use the context
29
+
30
+ - **Unresolved items** from the most recent session are the highest-priority carry-overs — address them before starting new work unless the user says otherwise
31
+ - **PR review todos** items are reviewer-requested changes — treat each unchecked box as a TODO to resolve, then reply on the PR (a Lumo comment mirrors back to GitHub)
32
+ - **Memory section** provides validated context that persists across sessions — use it to avoid re-learning decisions or constraints
33
+ - Focus on the **most recent 1–2 sessions** for relevant state; older sessions are for historical reference only
34
+ - If there are **no prior sessions**, this is a fresh start — read the task description carefully and ask clarifying questions if needed
35
+
36
+ ## Context Retrieval (full text on demand)
37
+
38
+ LUM-122 split task context injection into tiers. `lumo task context <LUM-N>`
39
+ now emits a **cheap inline card** for each source — a short summary or just
40
+ metadata — instead of dumping full bodies. Slack, docs, artifacts, and comments
41
+ get an **LLM summary**; web links, Figma, and PRs get **metadata only**. Each
42
+ card ends with the **retrieval command** you run to pull the heavy content on
43
+ demand.
44
+
45
+ **How to use it:** when the inline card is not enough and you need the full
46
+ Slack thread, the web page body, the Figma metadata, the entire comment thread,
47
+ or the PR detail — run the matching command below. Pass the same identifier
48
+ (`LUM-N`) plus the id the card shows for that source (a Slack `contextId`, a web
49
+ `linkId`, a Figma `linkId`, or a PR `number`).
50
+
51
+ All five are **read-only** (no live Slack/GitHub/Figma calls except the web body
52
+ fetch). Web/Figma/PR are v1 metadata-degraded: they print a `note:` explaining
53
+ that live content needs an external integration.
54
+
55
+ ### `lumo task slack show <identifier> <contextId>` — full Slack thread snapshot
56
+
57
+ Prints the **stored** thread snapshot (no live Slack call), one line per message
58
+ as `author: text`. Author falls back to `@<userId>` when the display name is
59
+ missing. Empty snapshot prints `(no messages in stored snapshot)`.
60
+
61
+ ```bash
62
+ lumo task slack show LUM-42 ctx_abc123
63
+ ```
64
+
65
+ ### `lumo task web show <identifier> <linkId>` — fetched web link body
66
+
67
+ Fetches the page body on demand behind the SSRF guard (cached after first read)
68
+ and prints it as plain text. Empty body prints `(empty body)`. Fetch failures
69
+ (blocked host, timeout) print the server's error message.
70
+
71
+ ```bash
72
+ lumo task web show LUM-42 wl_abc123
73
+ ```
74
+
75
+ ### `lumo task figma context <identifier> <linkId>` — Figma link metadata
76
+
77
+ **v1 metadata fallback.** Prints the cached design metadata as `file:` /
78
+ `frame:` / `url:` / `synced:` (and `syncError:` if the last sync failed) lines.
79
+ Live design context (layers, variables, code connect) requires the Figma MCP
80
+ server, so the command ends with a `note:` saying so.
81
+
82
+ ```bash
83
+ lumo task figma context LUM-42 cfl_abc123
84
+ ```
85
+
86
+ ### `lumo task comments list <identifier>` — full comment thread
87
+
88
+ Prints the **entire** comment thread: each comment as `author · createdAt`
89
+ followed by its plain-text body (comment bodies are stored as HTML and stripped
90
+ to text). Replies are indented two spaces under their parent. Author falls back
91
+ to `unknown`. No comments prints `(no comments)`.
92
+
93
+ ```bash
94
+ lumo task comments list LUM-42
95
+ ```
96
+
97
+ **Plural, and distinct from `task comment`.** `task comments list` _reads_ the
98
+ whole thread (this retrieval command). `task comment <identifier> <body>`
99
+ _writes_ a single new comment (see Task Management). Don't confuse the two —
100
+ the plural `comments` is read-only.
101
+
102
+ ### `lumo task pr show <identifier> <number>` — synced PR metadata
103
+
104
+ **v1 metadata fallback.** Prints the synced PR record: a `#<number> (repo)
105
+ title` header, then `state:` (with ` · draft` when draft), `ci:`, `author:`,
106
+ `branch: <head> → <base>`, and `url:` lines. The live diff + review comments
107
+ require the GitHub integration, so the command ends with a `note:` saying so.
108
+
109
+ ```bash
110
+ lumo task pr show LUM-42 128
111
+ ```
112
+
113
+ ## `lumo task lineage <id>`
114
+
115
+ Read-only audit view over the task's `LineageEdge` rows. Given a task
116
+ identifier (`LUM-N`), prints the causal trail:
117
+
118
+ - **Totals banner** — distinct sessions, fragment count, edge count,
119
+ total tokens (input/output/cache split) and loops, and the outcome
120
+ distribution.
121
+ - **One block per session** — the group's cost shown **once** (token/loop),
122
+ the date it consumed context, then each context fragment as
123
+ `[OUTCOME] TYPE — <source label>`, plus a per-group outcome summary.
124
+
125
+ Cost is attributed once per session (a session that injected many fragments is
126
+ not double-counted). Fragment ids are canonical — MEMORY fragments survive
127
+ consolidation drift.
128
+
129
+ **Cold start:** a task with no edges prints a friendly note (lineage is captured
130
+ when a session-bound run consumes the task's context), not an error.
131
+
132
+ **When to suggest:** the user wants to audit "what context did the AI actually
133
+ use, and what did it cost" for a task / merged PR — CFO / compliance / trust
134
+ narratives.
135
+
136
+ Entry point is the task identifier only; PR-number lookup is a future addition.
@@ -0,0 +1,357 @@
1
+ # Task Management
2
+
3
+ ## Task Management
4
+
5
+ ### `lumo task create <title> [flags]` — create a new task
6
+
7
+ Use this when the user wants to file a new task from the terminal. Title is positional and required (non-empty).
8
+
9
+ | Flag | Type | Notes |
10
+ | ------------------------ | ------ | ----------------------------------------------------------------------------------- |
11
+ | `-d, --description <>` | string | Optional task description. |
12
+ | `-p, --priority <level>` | enum | `low \| medium \| high \| urgent` (case-insensitive). Defaults to `low`. |
13
+ | `-a, --assignee <ref>` | string | `me`, an email, or a member name. Defaults to `me`. |
14
+ | `--project <ref>` | string | Project name or slug. **Required when the workspace has more than one project.** |
15
+ | `--milestone <ref>` | string | Milestone name (case-insensitive) within the resolved project. Omit for no binding. |
16
+ | `--sprint <ref>` | string | Sprint number or UUID to bind the task to on creation. Omit for no sprint binding. |
17
+ | `--tag <name>` | string | Attach a tag by name (repeatable). The name is resolved to an id server-side. |
18
+ | `--tag-id <cuid>` | string | Attach a tag by cuid (repeatable). Combines with `--tag`. |
19
+
20
+ Examples:
21
+
22
+ ```bash
23
+ lumo task create "Fix Slack OAuth redirect bug"
24
+ lumo task create "Refactor task service" --priority high --description "Split into smaller files"
25
+ lumo task create "Investigate slow query" --assignee teammate@example.com --project backend
26
+ lumo task create "Plan API design" --milestone "v1.0"
27
+ lumo task create "Sprint task" --sprint 3
28
+ lumo task create "Add rate limiting" --tag bug --tag urgent
29
+ lumo task create "Spike: evaluate caching options" --tag rfc --tag-id clm_abc123
30
+ ```
31
+
32
+ On success the command prints one or two lines to stdout:
33
+
34
+ ```
35
+ Created LUM-55 "Title" https://www.uselumo.ai/workspace/<slug>/my-tasks/LUM-55
36
+ Tags: bug, urgent
37
+ ```
38
+
39
+ The `Tags:` line is omitted when no tags were attached.
40
+
41
+ If the workspace has multiple projects and `--project` is omitted, the server will return an error naming available projects — re-run with `--project <slug>`.
42
+
43
+ ### When to suggest `task create`
44
+
45
+ - The user describes wanting a new task ("create a task to ...", "file a bug for ...", "log a TODO that ...", "add a task: ...").
46
+ - After a discussion that ends in "let's track that separately" — offer to create the task with a sensible title and priority.
47
+ - For follow-ups discovered mid-work that shouldn't bloat the current change — propose `task create` rather than silently expanding scope.
48
+
49
+ ### `lumo task update <identifier> [flags]` — patch a task
50
+
51
+ Pure flag-driven update. Provide at least one of:
52
+
53
+ | Flag | Type | Notes |
54
+ | ------------------------ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
55
+ | `-t, --title <text>` | string | Cannot be empty. |
56
+ | `-d, --description <>` | string | `--description ""` clears the field. |
57
+ | `-s, --status <value>` | enum | `todo \| in_progress \| in_review \| done` (case-insensitive). |
58
+ | `-p, --priority <lvl>` | enum | `low \| medium \| high \| urgent`. |
59
+ | `-a, --assignee <ref>` | string | `me`, an email, or a member name. `--assignee ""` clears the field. |
60
+ | `--milestone <ref>` | string | Milestone name (case-insensitive) within the task's project. `--milestone ""` unbinds. |
61
+ | `--sprint <ref>` | string | Sprint number or UUID to bind the task to. `--sprint ""` clears the current sprint binding (idempotent when already unbound). |
62
+ | `--tag <name>` | string (repeatable) | **Bulk replace** the tag set by name. Creates tag if missing. Max 20. Mutually exclusive with `--add-tag*` / `--remove-tag*`. |
63
+ | `--tag-id <cuid>` | string (repeatable) | **Bulk replace** the tag set by id. Max 20. Mutually exclusive with `--add-tag*` / `--remove-tag*`. |
64
+ | `--add-tag <name>` | string (repeatable) | Attach tag by name (find-or-create). Max 20. |
65
+ | `--add-tag-id <cuid>` | string (repeatable) | Attach tag by id. Max 20. |
66
+ | `--remove-tag <name>` | string (repeatable) | Detach tag by name. `--remove-tag <name>` resolves the name via find-or-create on the workspace. If the name was unknown, a new Tag row is created (orphan, no attachments) before the detach runs as a no-op. Use `--remove-tag-id <cuid>` to avoid orphans. Max 20. |
67
+ | `--remove-tag-id <cuid>` | string (repeatable) | Detach tag by id. Unknown ids are a no-op (no side effects). Max 20. |
68
+
69
+ `--tag` / `--tag-id` (bulk replace) are mutually exclusive with `--add-tag` / `--add-tag-id` / `--remove-tag` / `--remove-tag-id`. The CLI errors before any network call if both families are mixed.
70
+
71
+ Examples:
72
+
73
+ ```bash
74
+ lumo task update LUM-48 --status in_progress
75
+ lumo task update LUM-48 --title "Update task from CLI" --priority high
76
+ lumo task update LUM-48 --assignee me
77
+ lumo task update LUM-48 --description "" # clear description
78
+ lumo task update LUM-48 --assignee "" # unassign
79
+ lumo task update LUM-48 --milestone "v1.0" # attach to milestone
80
+ lumo task update LUM-48 --milestone "" # unbind milestone
81
+ lumo task update LUM-48 --sprint 3 # bind to sprint #3
82
+ lumo task update LUM-48 --sprint "" # unbind from current sprint
83
+ lumo task update LUM-42 --add-tag urgent --remove-tag draft
84
+ lumo task update LUM-42 --tag final --tag approved # replace entire tag set
85
+ lumo task update LUM-42 --tag final --add-tag oops
86
+ # Error: --tag/--tag-id are mutually exclusive with --add-tag/--add-tag-id/--remove-tag/--remove-tag-id
87
+ ```
88
+
89
+ On success the command prints one or two lines to stdout:
90
+
91
+ ```
92
+ Updated LUM-48 "Title" https://www.uselumo.ai/workspace/<slug>/my-tasks/LUM-48
93
+ Tags: urgent
94
+ ```
95
+
96
+ The `Tags:` line is omitted when the resulting tag set is empty.
97
+
98
+ ### Status transitions — direct moves are legal
99
+
100
+ The server's transition matrix (`lib/task/state-machine.ts`):
101
+
102
+ | From | Allowed targets |
103
+ | ----------- | --------------------------------------------------- |
104
+ | TODO | IN_PROGRESS, IN_REVIEW, DONE |
105
+ | IN_PROGRESS | TODO, IN_REVIEW, DONE |
106
+ | IN_REVIEW | TODO, IN_PROGRESS, DONE |
107
+ | DONE | TODO, IN_PROGRESS (reopen only — **not** IN_REVIEW) |
108
+
109
+ Practical rules:
110
+
111
+ - **One call suffices.** `--status done` straight from TODO or IN_PROGRESS is legal — never walk `in_progress → in_review → done` as a ritual (measured in LUM-392: 70 such chains wasted ~75 calls).
112
+ - **Under the verify flow you don't set `in_review`/`done` at all** — `lumo verify` moves the task to IN_REVIEW on all-pass and the DONE adjudication is human-only.
113
+ - **DONE → IN_REVIEW is rejected (409).** To attach follow-up context to a DONE task, use `lumo task comment` instead of reopening.
114
+
115
+ ### When to suggest `task update`
116
+
117
+ - The user describes a state change in natural language (e.g. "mark LUM-48 as in progress", "rename LUM-12 to ...", "assign LUM-30 to me", "bump the priority on LUM-7").
118
+ - After the agent finishes a task and the user confirms — offer to move it to `done`.
119
+ - Multiple status changes in a row should each be a separate `update` invocation rather than batched.
120
+
121
+ ### Sprint output format
122
+
123
+ `--sprint <ref>` prints a `Sprint:` line after the update line showing old → new binding:
124
+
125
+ ```
126
+ Sprint: - → #3 # newly bound (was backlog)
127
+ Sprint: #2 → #3 # rebound (moved from sprint 2 to 3)
128
+ Sprint: #3 → - # unbound
129
+ Task LUM-48 already in sprint #3 # noop (same sprint)
130
+ Task LUM-48 has no sprint binding # noop (already unbound)
131
+ ```
132
+
133
+ `--sprint` can be combined with other update flags. The PATCH (field updates) runs first; the sprint operation runs after. Failures on either step pass through independently without rollback.
134
+
135
+ ### Out of scope
136
+
137
+ The CLI does **not** currently update due date or parent task. Those need to be edited in the web UI.
138
+
139
+ Milestone updates (`--milestone`) and sprint binding (`--sprint`) both work. Full milestone CRUD is available via `lumo milestone create / show / update / delete`, tasks can be bound/unbound in bulk via `lumo milestone add / remove <identifier> <task...>`, and milestones can be manually reordered via `lumo milestone reorder <ref...>` / `lumo milestone move <ref> --before|--after <ref>` (see below). Full sprint CRUD is available via `lumo sprint create / show / update / delete / start / close / add / remove` (see below).
140
+
141
+ ### `lumo task list [flags]` — list tasks assigned to you
142
+
143
+ Default behavior: prints every task currently assigned to the authenticated user (no project / status filter), one per line, as a fixed-width table:
144
+
145
+ ```
146
+ LUM-42 IN_PROGRESS HIGH web Fix Slack OAuth redirect
147
+ LUM-48 TODO MEDIUM backend Investigate slow query
148
+ ```
149
+
150
+ | Flag | Type | Notes |
151
+ | ----------------------- | ------- | -------------------------------------------------------------------------------- |
152
+ | `-s, --status <value>` | enum | Filter by status: `todo \| in_progress \| in_review \| done` (case-insensitive). |
153
+ | `-p, --project <ref>` | string | Filter by project name (case-insensitive match against display name). |
154
+ | `-m, --milestone <ref>` | string | Filter to my tasks under this milestone (name or UUID). |
155
+ | `-n, --limit <count>` | integer | Cap output to the first N rows. |
156
+
157
+ When `--milestone` is set, the CLI calls `GET /api/milestones/<id>/tasks?assigned=me` instead of `/api/tasks/me`. Other filters (`--status`, `--limit`) still apply client-side to the milestone-scoped result.
158
+
159
+ Filtering is currently client-side — the server returns the full "my tasks" set and the CLI slices it. This is fine for typical workspaces (dozens of tasks); revisit if a workspace has hundreds.
160
+
161
+ ### When to suggest `task list`
162
+
163
+ - The user asks "what am I working on", "what tasks do I have", "list my tasks", "show me my queue".
164
+ - Before suggesting a status change ("mark something as done"), if no task ID is in context — run `task list` first to surface candidates.
165
+
166
+ ### `lumo next [--count <N>]` — recommend the next task to work on
167
+
168
+ Ranks the tasks assigned to you and prints the top N (default 3), each with a
169
+ one-line reason. Read-only — it does **not** bind or load context. Pick one from
170
+ the list, then run `lumo session attach <LUM-N>` + `lumo task context <LUM-N>`.
171
+
172
+ Ranking is lexicographic: **priority** (URGENT→LOW) first, then **active-sprint
173
+ membership**, then **due date** (earlier first), then in-flight status
174
+ (IN_PROGRESS / IN_REVIEW ahead of TODO). DONE tasks are excluded. The active
175
+ sprint lookup is best-effort — if it fails the command still recommends, just
176
+ without the sprint boost.
177
+
178
+ | Flag | Type | Notes |
179
+ | ----------------- | ------- | ----------------------------------------------------------------------- |
180
+ | `-n, --count <N>` | integer | How many tasks to recommend. Defaults to 3. Must be a positive integer. |
181
+
182
+ ```bash
183
+ lumo next
184
+ lumo next --count 1
185
+ ```
186
+
187
+ Output:
188
+
189
+ ```
190
+ Top 3 recommended tasks (of 12 open):
191
+
192
+ 1. LUM-42 IN_PROGRESS URGENT Fix Slack OAuth redirect
193
+ ↳ URGENT · active sprint · due 2026-06-03 (overdue) · in progress
194
+ 2. LUM-48 TODO HIGH Investigate slow query
195
+ ↳ HIGH · active sprint
196
+ 3. LUM-12 TODO MEDIUM Add rate limiting
197
+ ↳ MEDIUM · due 2026-06-10
198
+
199
+ Next: lumo session attach LUM-42 && lumo task context LUM-42
200
+ ```
201
+
202
+ When to suggest: the user asks "what should I work on", "what's next", "recommend my next task" (in any language), "pick my next task", or starts a session without a task in mind. After they choose, run `session attach` + `task context` for the picked task.
203
+
204
+ ### `lumo task show <identifier>` — print one task's detail
205
+
206
+ Returns a key:value block for a single task — title, status, priority, project, assignee (with display name from Clerk), URL, and the full description below. Lighter than `task context` because it does not load prior session summaries or memory.
207
+
208
+ ```bash
209
+ lumo task show LUM-42
210
+ ```
211
+
212
+ Use when the user wants the current state of a task without the agent-handoff payload.
213
+
214
+ ### `lumo task comment <identifier> <body>` — leave a comment
215
+
216
+ Two-step under the hood (resolve LUM-N → POST comment). Body is plain text; quote it to embed spaces or newlines.
217
+
218
+ ```bash
219
+ lumo task comment LUM-42 "Reproduced the redirect bug on staging — Safari only, not Chrome."
220
+ ```
221
+
222
+ The CLI does not support @-mention chip syntax. If the user wants to ping someone, they should comment from the web UI.
223
+
224
+ ---
225
+
226
+ ## Task Dependencies (`lumo task deps …`)
227
+
228
+ ### `lumo task deps list <LUM-N>` — show all dependency edges
229
+
230
+ Prints the task's dependency edges grouped into three sections: **CONFIRMED**, **SUGGESTED (pending confirmation)**, and **DISMISSED**. Each row includes a short 8-character edge id in square brackets, the direction (`blocked by` / `blocks`), the other task's identifier and title, the other task's current status, the source (`MANUAL` or `DETECTED`), and inline evidence for detected edges.
231
+
232
+ ```bash
233
+ lumo task deps list LUM-42
234
+ ```
235
+
236
+ Example output:
237
+
238
+ ```
239
+ Dependencies for LUM-42 (3)
240
+
241
+ CONFIRMED
242
+ [a1b2c3d4] blocked by LUM-9 "Fix auth token expiry" IN_PROGRESS · MANUAL
243
+
244
+ SUGGESTED (pending confirmation)
245
+ [e5f6a7b8] blocks LUM-55 "Migrate DB schema" TODO · shared_files(4 shared files: src/db/schema.ts, src/db/migrate.ts, ...)
246
+ confirm: lumo task deps confirm LUM-42 e5f6a7b8 (add --reverse if direction is flipped; false positive: dismiss)
247
+ [c9d0e1f2] blocked by LUM-38 "Add OAuth scopes" IN_REVIEW · task_mention(description)
248
+ confirm: lumo task deps confirm LUM-42 c9d0e1f2 (add --reverse if direction is flipped; false positive: dismiss)
249
+
250
+ DISMISSED
251
+ [b3c4d5e6] blocks LUM-12 · dismissed
252
+ ```
253
+
254
+ CONFIRMED and SUGGESTED rows show the other task's identifier, title, current status, and source/evidence. DISMISSED rows render as `[shortId] <direction> <identifier> · dismissed` only — no title, status, or source.
255
+
256
+ When there are no edges at all the output is:
257
+
258
+ ```
259
+ Dependencies for LUM-42: no dependency edges.
260
+ ```
261
+
262
+ **Evidence fields by detection signal:**
263
+
264
+ - `shared_files` — `shared_files(N shared files: path1, path2, …)` — number of shared write-touched files in the 14-day window, plus up to 5 sample paths.
265
+ - `task_mention` — `task_mention(description)` or `task_mention(comment)` — the surface where the mention appeared.
266
+
267
+ CONFIRMED rows also show `source`: `MANUAL` (user-declared via `deps add`) or `DETECTED` (auto-found then confirmed via `deps confirm`).
268
+
269
+ ### `lumo task deps add <LUM-N> --blocked-by <LUM-M>` — declare a manual hard dependency
270
+
271
+ Asserts that LUM-N is blocked by LUM-M. The edge is created as CONFIRMED + MANUAL, meaning it is immediately in effect (no confirmation step required).
272
+
273
+ ```bash
274
+ lumo task deps add LUM-42 --blocked-by LUM-9
275
+ ```
276
+
277
+ Both `<LUM-N>` and `--blocked-by` are required. The command errors on usage if either is missing.
278
+
279
+ **Service semantics (read before using):**
280
+
281
+ - **Self-edge** → 400 ("A task cannot depend on itself").
282
+ - **CONFIRMED edge in the same direction already exists** → 409 ("Dependency already exists").
283
+ - **CONFIRMED edge in the reverse direction already exists** → the cycle guard fires and returns 409 ("Dependency would create a cycle").
284
+ - **Pair has a SUGGESTED or DISMISSED edge** in the same direction → `add` confirms it in place, preserving the original DETECTED source (so the edge transitions to CONFIRMED while keeping its auto-detected provenance). No new row is created.
285
+ - **Cycle guard** — the service runs a DFS over all CONFIRMED BLOCKS edges in the workspace before writing. If adding the edge would create a cycle → 409 ("Dependency would create a cycle").
286
+
287
+ ### `lumo task deps confirm <LUM-N> <edge> [--reverse]` — confirm a detected candidate
288
+
289
+ Promotes a SUGGESTED edge to CONFIRMED. `<edge>` is a selector for the specific edge on LUM-N's edge list.
290
+
291
+ ```bash
292
+ lumo task deps confirm LUM-42 e5f6a7b8 # confirm as detected direction
293
+ lumo task deps confirm LUM-42 LUM-55 # selector by other task's identifier
294
+ lumo task deps confirm LUM-42 e5f6a7b8 --reverse # flip direction before confirming
295
+ ```
296
+
297
+ **Edge selector semantics** (shared by `confirm`, `dismiss`, `rm`):
298
+
299
+ - **Other task's identifier** (e.g., `LUM-55`) — case-insensitive exact match against the edge's other-task identifier. Resolves unambiguously when there is exactly one edge to that task.
300
+ - **Edge-id prefix** — at least 6 characters of the short id (e.g., `e5f6a7`). Must match exactly one edge.
301
+ - If zero or more than one edge matches → prints all candidate edges with short ids and exits 1. Retry with a more specific selector.
302
+
303
+ **`--reverse` semantics:**
304
+
305
+ - The detector's direction heuristic is best-effort. If the suggested direction is backwards (e.g., the detector says "LUM-42 blocks LUM-55" but actually LUM-55 blocks LUM-42), confirm with `--reverse` to flip before writing.
306
+ - The service checks that the reversed pair does not already have an edge (→ 409), and re-runs the cycle guard with the flipped direction.
307
+
308
+ ### `lumo task deps dismiss <LUM-N> <edge>` — dismiss a candidate (immune to re-detection)
309
+
310
+ Marks the edge DISMISSED. The row is kept in the database — this is the key difference from `rm`. Because the row exists (in either direction), the detection service will never re-suggest this pair.
311
+
312
+ ```bash
313
+ lumo task deps dismiss LUM-42 e5f6a7b8
314
+ lumo task deps dismiss LUM-42 LUM-38
315
+ ```
316
+
317
+ Output: `Dismissed: [e5f6a7b8] LUM-38 "Add OAuth scopes" (won't be suggested again)`
318
+
319
+ Use `dismiss` for false positives. Use `rm` only when you want the pair to be eligible for re-detection in the future (the detection service can re-suggest pairs with no existing row).
320
+
321
+ ### `lumo task deps rm <LUM-N> <edge> --yes` — delete an edge
322
+
323
+ Hard-deletes the edge row. **Requires `--yes`** — the CLI refuses without it (no interactive prompt exists).
324
+
325
+ ```bash
326
+ lumo task deps rm LUM-42 a1b2c3d4 --yes
327
+ ```
328
+
329
+ Output: `Removed [a1b2c3d4] from LUM-42`
330
+
331
+ **`rm` vs `dismiss`:** deleting removes the immunity — the detection service may re-suggest this pair the next time a shared-files sweep or task-mention event fires. Prefer `dismiss` for detection false positives; use `rm` to remove an incorrectly-declared MANUAL edge that you want fully erased.
332
+
333
+ ---
334
+
335
+ ### Detection red lines
336
+
337
+ - The detection service **never creates CONFIRMED edges automatically**. All auto-detected candidates are SUGGESTED; a human must `confirm` or `add` for an edge to become CONFIRMED.
338
+ - **Dismiss is pair-wise immunity**: once any edge exists between task A and task B (in either direction, regardless of status including DISMISSED), the detection service will not create a new candidate for that pair.
339
+ - **`rm` lifts the immunity**: after deleting the only edge between A and B, the detector may re-suggest them on the next event or sweep.
340
+
341
+ ---
342
+
343
+ ### Detection signals
344
+
345
+ **Signal 1 — `task_mention`**: fires when a task's description is updated or a comment is created. If the updated HTML contains @-mentions of other tasks, the mentioning task is recorded as depending on the mentioned task (direction heuristic: mentioner blocked by mentioned). Triggers immediately on write events; no cron needed.
346
+
347
+ **Signal 2 — `shared_files`**: hourly cron sweep. Looks at write-tool hook events (file edits, creates, etc.) in the past 14 days. For every pair of open (non-DONE) tasks that share **≥ 3 written files**, a SUGGESTED edge is created. Direction heuristic: older task blocks newer task. Parent–child task pairs are skipped (they share files by design). Edges are not created across different workspaces.
348
+
349
+ ---
350
+
351
+ ### When to suggest `task deps` commands
352
+
353
+ - **After `session attach` output shows a blocker warning or candidate-count hint** → run `lumo task deps list <LUM-N>` to review the full edge list, then `confirm` or `dismiss` each SUGGESTED candidate.
354
+ - **User says "X needs to wait for Y" or "LUM-42 is blocked by LUM-9"** → run `lumo task deps add LUM-42 --blocked-by LUM-9`.
355
+ - **Agent sees a `## ⚠ Dependency alerts` block (form A — live blockers) at session-start** → evaluate whether to wait for the blocker to merge before starting work; if the edge is stale or wrong, clean it with `deps rm` or `deps dismiss`.
356
+ - **Agent sees only a standalone hint line `Detected N candidate dependencies awaiting confirmation…` (form B — no live blockers)** → no immediate blocker, but run `lumo task deps list <LUM-N>` to review and confirm/dismiss SUGGESTED candidates. See [sessions.md](sessions.md) for the full alert format.
357
+ - **User reports a false positive dependency suggestion** → `lumo task deps dismiss <LUM-N> <edge>` to permanently suppress it for this pair.