@ritualai/cli 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ritualai/cli",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "Ritual CLI — scaffold AI coding agent skills + register MCP servers. Connects Claude Code, Cursor, Windsurf, Kiro, Gemini CLI, VS Code/Copilot, and Codex to Ritual Cloud.",
5
5
  "private": false,
6
6
  "license": "Apache-2.0",
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879
 
@@ -1,4 +1,4 @@
1
1
  {
2
- "cliVersion": "0.9.4",
3
- "builtAt": "2026-05-21T14:03:29.145Z"
2
+ "cliVersion": "0.9.6",
3
+ "builtAt": "2026-05-21T21:15:18.746Z"
4
4
  }
@@ -176,7 +176,7 @@ If the user replies `suggest` but the workspace has no prior explorations, expla
176
176
  1. You just created the workspace in Step 1 (in-session creation — there are no explorations possible yet).
177
177
  2. The bound workspace's `_count.explorations === 0` (server-side, read from the `list_workspaces` call in Step 1). This is authoritative against any source of mutation — web UI, other agents, out-of-band API calls.
178
178
 
179
- If either fires, emit a single line and proceed straight to Step 2:
179
+ If either fires, emit a single line and proceed straight to Step 2. **This skip covers ALL of Step 1.5 — including step 8 (the `check_exploration_overlap` call). No `list_explorations`, no `check_exploration_overlap`, no resume picker. There is nothing to compare against in an empty workspace; running either tool is pure overhead that resolves to "nothing here" after a wasted MCP roundtrip + LLM cost + an interactive permission prompt the user has to approve.**
180
180
 
181
181
  > No prior work in this workspace — starting fresh.
182
182
 
@@ -405,7 +405,9 @@ Steps:
405
405
 
406
406
  Don't run the suggester from an empty workspace — there's no priors signal yet, and the user opening Ritual for the first time has stronger user-driven intent than the suggester could offer.
407
407
 
408
- 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" (or there were no existing explorations to resume) — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
408
+ 8. **Before the user commits to "start fresh"** — if they DID say "start fresh" AND the workspace has existing explorations to compare against — run a **semantic overlap check** against the workspace. This catches the case where what the user is describing is a near-duplicate of something that already exists, BEFORE they burn LLM cost on Steps 4-5:
409
+
410
+ **Skip this overlap check entirely when the workspace has zero explorations.** Two signals count as proof the workspace is empty: (a) you just created the workspace in Step 1 (in-session creation), or (b) `list_workspaces._count.explorations === 0` for the bound workspace (server-side count from the Step 1 call). With zero existing explorations, there's literally nothing to overlap with — the call would return `candidates: []` after a wasted MCP roundtrip + LLM cost + (in interactive permission modes) a needless user approval prompt. This was an oversight in cli 0.9.3's empty-workspace skip path: the top of Step 1.5 correctly said "proceed straight to Step 2", but this step 8 instruction still ran the overlap check when there was nothing to overlap with. Fixed in cli 0.9.5.
409
411
 
410
412
  Call `mcp__ritual__check_exploration_overlap(workspace_id, raw_input)`. Pass the user's full natural-language description of what they want to explore as `raw_input` — the SAME text you'd later pass to `generate_considerations`.
411
413
 
@@ -1843,7 +1845,7 @@ If you only want a subset, `drop` the recs you don't want first, then `accept re
1843
1845
 
1844
1846
  Notes on the detail card:
1845
1847
 
1846
- - **Single-rec accept is NOT a visible CTA here** the SKILL deliberately omits `accept R7`. The backing API only supports accept-all (`accept_recommendations`) today; surfacing `accept R7` would teach the user a command the system can't fulfill. When a single-rec accept endpoint lands (see backlog), re-introduce it here.
1848
+ - **Per-rec and subset accept are first-class CTAs as of cli 0.9.6.** The MCP `accept_recommendations` tool now takes an optional `recommendation_ids: string[]` param: omit it to bulk-accept everything (legacy), or pass a subset to promote only those rec IDs. Surface `accept R7` (single from detail), `accept R5,R8,R12` (subset from landing), and `accept recommended` (all) as the three accept-shaped CTAs. The agent accumulates the approved subset across the one-by-one walk-through and submits ONE batch call at the end — not N individual calls.
1847
1849
  - The 4-line "Why this" block is a transformation of the chained-arrow `rationale` string. The arrow chain is fine as a one-line summary at the very bottom if helpful, but the 4-named-line form is the primary readable shape.
1848
1850
  - `Tactics` and `Acceptance criteria` are related but distinct: tactics are SHORT IMPERATIVE STEPS ("Call Django authenticate() / login() through configured backends"); acceptance criteria are PASS CONDITIONS ("Valid inline registration creates exactly one user and authenticates the session").
1849
1851
  - `References` come from `metadata.explainability.faq_references` (subject + question text) AND `referenced_faq_ids` (which the agent can resolve back to the underlying source files / RBs if known).
@@ -1855,20 +1857,23 @@ Visible CTAs in 9.1 / 9.3 map to MCP/API actions. Some are direct, some require
1855
1857
 
1856
1858
  | User reply | Action | Backing call |
1857
1859
  |---|---|---|
1858
- | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations(exploration_id)` (admin only see Branch B) |
1860
+ | `accept recommended` | Accept ALL recs currently on screen | `mcp__ritual__accept_recommendations({ exploration_id })` (omit `recommendation_ids` — admin only, see Branch B) |
1861
+ | `accept R{N}` (from detail) | Mark that single rec approved (batch of 1) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuid_for_R{N}] })`. Exploration stays in REVIEWING_RECOMMENDATIONS if other recs remain in draft/pending; transitions to COMPLETE once nothing remains. |
1862
+ | `accept R{N},R{M},R{P}` (subset from landing) | Mark that subset approved (batch of N) | `mcp__ritual__accept_recommendations({ exploration_id, recommendation_ids: [rec_uuids…] })`. Single round-trip — don't loop N calls. |
1859
1863
  | `detail R{N}` | Render the detail card for that rec | None (in-memory) |
1860
- | `accept R{N}` (from detail) | Mark that single rec approved | **No direct single-rec API today — NOT shown as a visible CTA.** If user types it anyway, explain: "I can accept all 11 now via `accept recommended`, or you can `drop` the ones you don't want first." See backlog. |
1861
1864
  | `change R{N}: <edit>` | Regenerate that single rec with the user's hint | `mcp__ritual__regenerate_recommendation(recommendation_id, hint)` if available; else queue as a comment + ask the user to wait for re-gen |
1862
1865
  | `drop R{N}` | Mark that rec rejected | `update_recommendation` with status=rejected, OR add a "deliberately excluded" note for the brief generator |
1863
1866
  | `add <topic>` | Request a new rec on the topic | See § 9.1 note — typically requires full regenerate with the new topic pinned; SKILL surfaces the choice to the user before triggering |
1864
1867
  | `show scope` | Expand the scope reference | None (in-memory) |
1865
1868
  | `hold` | Stop here without accepting | None (exits the flow; user can resume later) |
1866
1869
 
1867
- Don't display all aliases. Display the four most-likely-needed: `accept recommended`, `detail R{N}`, `drop R{N}`, `hold`. Show `change R{N}: <edit>` and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1870
+ Don't display all aliases. Display the most-likely-needed: `accept recommended`, `accept R{N}` (single), `detail R{N}`, `drop R{N}`, `hold`. Show `accept R{N},R{M}` (subset), `change R{N}: <edit>`, and `add <topic>` in the detail card or as a one-line hint when the landing screen is presented for the second time (the user knows the basics by then).
1871
+
1872
+ **Subset-accept agent behavior — one call, not N:** when the user types `accept R5,R8,R12` (or accumulates approvals across the one-by-one walkthrough), the agent collects the rec UUIDs in memory and submits a SINGLE `accept_recommendations({ exploration_id, recommendation_ids })` call. Do not loop and call the tool once per rec — the API + downstream artifact-trigger is designed for one batch per "user is done with this set" event. Multiple calls inflate latency, multiply the triage-complete event emission, and cause duplicate auto-artifact queueing.
1868
1873
 
1869
1874
  **Backlog notes** (referenced for the agent so it doesn't over-promise):
1870
- - Single-rec `accept R7` from the detail card doesn't have a direct API endpoint — today the user can either accept ALL or none. Surface this honestly: "I can accept all 11 now, or you can drop the ones you don't want and then accept the rest."
1871
1875
  - `add <topic>` requires a regenerate with a pinned topic — that's a forthcoming `regenerate_recommendation` improvement; until then it's a full regeneration cycle.
1876
+ - Per-rec MCP `reject` (status=rejected) doesn't have a dedicated MCP tool yet. For now, `drop R{N}` is handled via the web's per-rec PATCH OR by the user simply not including it in the batch-accept call (it stays in draft/pending until the user explicitly accepts or rejects it). Adding `reject_recommendation` MCP tool is on the backlog.
1872
1877
 
1873
1878
  ##### 9.A — Branch A: admin replies `accept recommended`
1874
1879