slidemind 0.1.6 → 0.1.8

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": "slidemind",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Connect Claude Code, Codex & opencode to the slidemind PowerPoint add-in — let your coding agent build and edit native, on-brand PowerPoint decks against your active corporate design, from the terminal.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,9 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@clack/prompts": "^1.3.0",
34
- "@modelcontextprotocol/sdk": "^1.29.0",
35
- "puppeteer": "24.43.0",
36
- "zod": "^3.23.8"
34
+ "puppeteer": "24.43.0"
37
35
  },
38
36
  "engines": {
39
37
  "node": ">=18"
@@ -50,7 +48,6 @@
50
48
  "claude-plugin",
51
49
  "codex",
52
50
  "opencode",
53
- "mcp",
54
51
  "skill"
55
52
  ],
56
53
  "author": "statworx",
@@ -11,17 +11,37 @@ This skill is **thin workflow glue for the local harness**. Everything that dete
11
11
  - The **authoring workflow craft** — create, edit, composition, layouts, authoring contract, build/export — is the add-in's deployment-shipped `workflow/*.md`, served on the same bundle so the local harness reads **byte-identical** guidance to the in-app design agent.
12
12
  - The **`.pptx` render** happens server-side in the add-in. There is no local exporter.
13
13
 
14
- So this file owns only what is genuinely CLI-specific: the **host precondition**, a compact **intake/plan**, the **create flow**, and the **command mapping** that translates the add-in's in-app tool names (used throughout the bundle's `workflow/*.md`) into your `slidemind` commands and MCP tools. Read the workflow + brand from the bundle; never restate or duplicate them here.
14
+ So this file owns only what is genuinely CLI-specific: the **first-step design-bundle gate**, a compact **intake/plan**, the **create flow**, and the **command mapping** that translates the workflow vocabulary — the harness-neutral verbs defined in the bundle's `workflow/flow.md` and spoken throughout `workflow/*.md` — into your `slidemind` CLI commands. Read the workflow + brand from the bundle; never restate or duplicate them here.
15
+
16
+ **slidemind is a CLI you drive directly.** Run `slidemind <command>` in your shell — the same way you'd run `git` or `npm`. There is no separate tool layer to go through; every step below is a real command you type.
17
+
18
+ ## Create a todo list (before your first command)
19
+
20
+ The moment this skill activates on an authoring task, **create a todo list of the workflow stages** in your harness's task tracker — before you run anything — and keep it current: mark each stage done as you complete it. This is `workflow/flow.md` → *track the stages*; the list is what keeps the later stages (above all the review gate) from being skipped. The stages, as they run over the CLI:
21
+
22
+ 1. `slidemind ready` — session preflight (*First step* below)
23
+ 2. Clarify with the user — the content **and the output target** (*Intake → plan* below; needs no host, so it can run while `ready` executes)
24
+ 3. Plan sign-off — `slidemind plan <deck>` (decks; single slides stay in chat)
25
+ 4. Author the slides
26
+ 5. Draft check — `slidemind view-draft`
27
+ 6. Review gate — `slidemind review`, the moment the deck builds clean
28
+ 7. Deliver — `slidemind push` or `slidemind build-pptx`, whichever target was locked in stage 2
29
+
30
+ **Deliver is the last todo — the task ends when the slides are delivered.** Don't add a "sanity pass" or "report back" step after it: the visual QA already happened at the draft check and the user already approved at the review gate, so on approval you push/build directly and stop. Each stage's full definition and the ordering invariants live in the bundle's `workflow/flow.md` — read it right after `ready` succeeds. The invariant you must never break: **never jump from authoring to deliver** — the draft check and an approved review gate always sit between.
15
31
 
16
32
  ## Bootstrap (set yourself up — don't make the user do it)
17
33
 
18
- This skill drives the `slidemind` CLI + its MCP server (`slidemind_list_open_presentations`, `slidemind_push_deck`, `slidemind_search_engine`, `slidemind_download_result`). The CLI reaches PowerPoint through the add-in's **cloud relay** — it doesn't run any local server. Patch what's missing yourself, but the **pairing** step needs the user once (they hold the add-in's identity):
34
+ **The first step of every session is `slidemind ready`** (continuing an existing deck: `slidemind ready <deck>`). In one call it verifies pairing, connection, and CLI version; resolves the design the add-in has open; downloads or refreshes that design's bundle; and — given a deck arg — binds the deck to it.
35
+
36
+ - **Exit 0** → you're fully set up. Read `workflow/flow.md` (the stage spine) and `design.md` from the reported `bundleDir` and start planning.
37
+ - **Non-zero** → the CLI names exactly one blocker and one `nextAction`; do what it says. (The two blockers that ever need the user are handled in *First step* below.)
38
+
39
+ `ready` drives the `slidemind` CLI, which reaches PowerPoint through the add-in's **cloud relay** — no local server. Patch a missing CLI yourself; **pairing** needs the user once (they hold the add-in's identity):
19
40
 
20
- - **CLI missing** (`slidemind` not on `PATH`, or the `slidemind_*` MCP tools absent): `npm install -g slidemind`, then `slidemind init --for <claude|codex|opencode|all>` (registers the MCP server + (re)deploys this skill). The harness may need a restart for the `slidemind_*` tools to appear.
21
- - **Not paired** (a command says *slidemind is not paired*): the one step you can't do for the user — they hold the add-in's identity. Walk them through **Pairing the CLI with the add-in** below (it carries the restart step the in-app wizard never mentions). `slidemind whoami` lists every paired environment.
22
- - `npx slidemind <command>` runs one-off without a global install; `slidemind --version` confirms PATH; `slidemind update` upgrades (`--ref <version>` to pin).
41
+ - **CLI missing** (`slidemind` not on `PATH`): `npm install -g slidemind`, then `slidemind init --for <claude|codex|opencode|all>` ((re)deploys this skill). `npx slidemind <command>` runs one-off without a global install; `slidemind --version` confirms PATH; `slidemind update` upgrades (`--ref <version>` to pin).
42
+ - **Not paired** (`ready` blocks with `not_paired`, or a command says *slidemind is not paired*): the one step you can't do for the user. Walk them through **Pairing the CLI with the add-in** below (it carries the restart step the in-app wizard never mentions). `slidemind whoami` lists every paired environment.
23
43
 
24
- After pairing once: **CLI paired + the add-in open ≡ it just works**, against whatever environment (dev / prod / a client deployment) the add-in is wired to. The CLI is **multi-environment**: pair once per backend (local / dev / prod) and every command fans out across all of them, tags each open window with its `env`, and routes to the right backend automatically — no manual switching. (Scope to one with `--backend <url|env>` when you need to.)
44
+ The CLI is **multi-environment**: pair once per backend (local / dev / prod) and every command fans out across all of them, tags each open window with its `env`, and routes to the right backend automatically — no manual switching. (Scope to one with `--backend <url|env>` when you need to.) A normal user pairs exactly one.
25
45
 
26
46
  ## Pairing the CLI with the add-in (one-time; you guide the user)
27
47
 
@@ -34,87 +54,92 @@ Pairing is the **only** step that genuinely needs the user — the pairing code
34
54
 
35
55
  **2 — Run the pair command in this terminal.** Have the user copy the step-3 `slidemind pair <code>` line and paste it here; run it. The code is single-use and expires (~10 min) — if it fails as expired/invalid, have them press **Pair** again for a fresh one. On success the add-in's Connect CLI panel flips to **Connected**.
36
56
 
37
- **3 — Restart the add-in once (the wizard does NOT tell the user this).** Pairing flips CLI integration on, but the task pane that's *already running* often won't pick up the live connection — so the freshly-paired window may not show up yet. **If, right after pairing, `slidemind presentations` still doesn't list the window** (or a push/search behaves as though nothing is connected) even though PowerPoint is open with the add-in loaded and a corporate design active, tell the user to **restart the add-in**: close the slidemind task pane and reopen it from the ribbon; if the window still doesn't appear, close and reopen the presentation (or PowerPoint). A fresh pane re-reads the now-enabled pairing and registers itself so the CLI can see it. Then re-run `slidemind presentations`. This is a one-time nudge right after the first pairing — once the window appears it stays, and the add-in can't trigger this restart itself, so you have to ask for it.
57
+ **3 — Restart the add-in once (the wizard does NOT tell the user this).** Pairing flips CLI integration on, but the task pane that's *already running* often won't pick up the live connection — so the freshly-paired window may not show up yet. **If, right after pairing, `slidemind ready` still reports no window** (a `no_window` blocker) even though PowerPoint is open with the add-in loaded and a corporate design active, tell the user to **restart the add-in**: close the slidemind task pane and reopen it from the ribbon; if the window still doesn't appear, close and reopen the presentation (or PowerPoint). A fresh pane re-reads the now-enabled pairing and registers itself so the CLI can see it. Then re-run `slidemind ready`. This is a one-time nudge right after the first pairing — once the window appears it stays, and the add-in can't trigger this restart itself, so you have to ask for it.
38
58
 
39
- **Two states, two different fixes — don't conflate them:**
59
+ ## First step — `slidemind ready` (before anything else, every time)
40
60
 
41
- | What you see | What it means | What to tell the user |
42
- |---|---|---|
43
- | *slidemind is not paired* (or empty `whoami`) | this machine has no session | mint a code via **Connect CLI** and run `slidemind pair <code>` (steps 1–2) |
44
- | `slidemind presentations` is **empty**, but PowerPoint is open with the add-in + a CD active, **and** this machine is already paired | the pane hasn't registered on the relay — typically a just-paired pane that needs a fresh boot | **restart the add-in** (step 3), then retry |
45
- | `slidemind presentations` is **empty** and no PowerPoint is connected | nothing to talk to | open PowerPoint, load the add-in, pick/create a corporate design |
61
+ Everything about how a deck is authored, styled, and rendered is shaped by the corporate design **the add-in has open**, and every brand rule you follow is read from that design's **materialized bundle**. `slidemind ready` gets you there in one call: it walks the connection ladder (pairing → reachable backend → CLI version → an open render-ready window), resolves which open design to build against, downloads or refreshes that design's bundle (incremental — unchanged files cost nothing), and — when you pass a deck — binds the deck to it by writing `<deck>/.bundle-ref.json`.
46
62
 
47
- ## Precondition gate (check this first, every time)
63
+ - **New work:** `slidemind ready` — resolves + materializes the open design's bundle so you can read its `design.md` while planning.
64
+ - **Continuing a deck:** `slidemind ready <deck>` — same, and (re)binds the deck to whatever design is open.
48
65
 
49
- Authoring and rendering hard-require an **open PowerPoint host with the slidemind add-in loaded and an active corporate design**. Without a host there is no bundle to read and no renderer to push to; `download-bundle`, `build-pptx`, and `push` all fail.
66
+ **The open add-in is the source of truth.** `ready` binds to whatever design is open *now*; a deck's `.bundle-ref.json` records the last-resolved design for the render-time etag contract and host-free bundle reads — it is **not** a pinned design preference. So you never "start a session with design A" from a deck ref; you start it from what the add-in has open.
50
67
 
51
- 1. Run `slidemind presentations` (or MCP `slidemind_list_open_presentations`).
52
- 2. One registered → that's your target `presentation_id`. **Several → ask the user which**, by `title`/`fileName` (never raw ids) — once for **which presentation's corporate design to download**, and again at render time for **which presentation to push into** (the CD source and the push target may be different presentations).
53
- 3. **None registered → stop.** Tell the user: *open PowerPoint, load the slidemind add-in, and pick or create a corporate design, then retry.*
68
+ **On exit 0** the JSON reports `presId`, `presFP`, `designName`, `bundleDir`, `bundleEtag`, `bound`, and `paneSuspended`, with `nextAction: "Ready."`. Read `workflow/flow.md` and `design.md` from `bundleDir` (cached at `${XDG_CACHE_HOME:-~/.cache}/slidemind/bundles/<presFP>/`, alongside `corporate-design.css`, `layouts/*.jsx`, `layouts/layouts.css`, `assets/`, `samples/`, `engines.json`, and the rest of the add-in-owned `workflow/*.md`) and start planning. A render-ready window whose pane is suspended still exits 0 with `paneSuspended: true` — push/search/read wait for a pane click on their own; **don't treat it as a blocker.**
54
69
 
55
- > **Empty list vs. not paired — different fixes** (full triage in *Pairing the CLI with the add-in* above). An *empty* registry with no PowerPoint connected means open it / enable Connect CLI (step 3). A *not paired* error means this machine has no session — pair once via the add-in's **"Connect CLI"**; don't ask them to open PowerPoint for that. An *empty* registry **while** PowerPoint is open with the add-in **and** this machine is already paired usually means the just-paired pane never registered — ask the user to **restart the add-in** (close + reopen the task pane), then retry.
70
+ **A bound deck can be ready with NO window at all.** `slidemind ready <deck>` for a deck that was bound once before may exit 0 with `windowless: true` even when no PowerPoint window is registered — the design identity lives in the deck's `.bundle-ref.json` and the bundle syncs over a pane-free route. In that state authoring, `view-draft`, `build`, `review`, and `build-pptx` all work end-to-end (PowerPoint backgrounded or closed); only `push`'s insert, `search`, and `read` need a window — the `nextAction` says exactly that. Don't ask the user to open PowerPoint until one of those pane ops is actually next.
56
71
 
57
- **Backgrounded PowerPoint is expected to work.** Do not pre-emptively ask the user to focus PowerPoint or the task pane, and never ask them to keep it foregrounded while something runs. The render itself (`build-pptx`, the render half of `push`) **never needs the task pane awake** — it captures the slides with a local headless browser and assembles the `.pptx` server-side — streams its own `rendering slide n/m…` progress, and survives long decks. Only the pane-touching ops (the insert half of `push`, engine search/download) need the pane, and the CLI handles that itself: it waits up to ~2 min, prints one *"click the slidemind pane"* line when user help is genuinely needed, and retries safely. If you see that line, relay it once and keep waiting — do not rebuild, re-plan, or babysit. If a `push` still times out, the rendered `.pptx` was saved next to the deck (`paneSuspended` + `fallbackFile` in the result) — nothing is lost; retry the push after the user clicks the pane. Reserve the full "open PowerPoint…" instruction in (3) for when nothing is registered at all.
72
+ **On non-zero** the CLI names exactly one blocker `{code, actor, message}` and one `nextAction`. **The CLI owns the remediation text — relay `nextAction`, don't restate it.** Only two blockers ever need the user:
58
73
 
59
- Local HTML preview (`slidemind build`) runs offline, but it reads a **previously materialized bundle** — so the host must have been available at least once.
74
+ - **`ambiguous_design`** — several windows with **different** corporate designs are open, so `ready` can't choose. The CLI lists the candidates (each with its `env` and window `title`/`fileName`, plus a design fingerprint); if the deck was last built against one of them it's marked `suggested`. **Ask the user which design to build against, naming the windows by `title`/`fileName` (and `env`) — never by raw id** — and mention the suggested one if present ("this deck was last built against X — continue with it?"). Then re-run `slidemind ready --to <presId>` for the window they pick.
75
+ - **Connection blockers** (`not_paired`, `all_unreachable`, `cli_update_required`, `no_window`, `not_render_ready`) — relay the CLI's `nextAction` verbatim (pair / open PowerPoint / click the pane / run `slidemind update`). Pairing is walked through in *Pairing the CLI with the add-in* above. (`no_window` only ever surfaces for an **unbound** deck or deckless `ready` — a bound deck rides the pane-free rung above instead.)
76
+
77
+ **The session spine** (= the stage todos you created up front): `slidemind ready` → read `workflow/flow.md` + `design.md` from `bundleDir` → intake/plan (below) → `slidemind new <slug>` (scaffolds **and** auto-binds the deck to the open design — zero extra download, because `ready` already materialized it) → `slidemind plan <slug>` (plan sign-off gate for decks; single slides stay in chat) → author → `view-draft` → `review` (mandatory, the moment the deck builds clean) → deliver (`push` / `build-pptx`). `slidemind new` best-effort binds when the open design is unambiguous and the bundle is already materialized; if it can't (ambiguous, or no host), it scaffolds anyway and hints to run `slidemind ready <slug>`.
78
+
79
+ **Backgrounded — or closed — PowerPoint is expected to work.** Do not pre-emptively ask the user to focus PowerPoint or the task pane, and never ask them to keep it foregrounded while something runs. The render itself (`build-pptx`, the render half of `push`) **never needs a window** for a bound deck — it captures the slides with a local headless browser and assembles the `.pptx` server-side over the pane-free brand route, streams its own `rendering slide n/m…` progress, and survives arbitrarily long authoring sessions (the old "author 30 minutes and the add-in is gone" failure no longer applies). Only the pane-touching ops (the insert half of `push`, engine search/download, `read`) need a live pane, and the CLI handles that itself: it waits up to ~2 min, prints one *"click the slidemind pane"* line when user help is genuinely needed, and retries safely. If you see that line, relay it once and keep waiting — do not rebuild, re-plan, or babysit. If a `push` can't deliver (pane never woke, or no window at all), the rendered `.pptx` was saved next to the deck (`paneSuspended` + `fallbackFile` in the result) — nothing is lost; re-run the push once a window exists. Reserve the full "open PowerPoint…" instruction for when a command actually reports it as the blocker.
80
+
81
+ `slidemind build`, `review`, and `view-draft` run offline, but only against a **previously materialized** bundle — so `ready` (or a prior `ready`) must have succeeded at least once. `build-pptx` additionally needs the backend reachable (the OOXML assembly is server-side), but no PowerPoint window for a bound deck.
60
82
 
61
83
  ## Intake → plan (you own this; do it in chat)
62
84
 
63
- The add-in's in-app flow has a manager do planning (`present_plan_for_review`); **here, you run it directly with the user.** Don't write slide JSX until the plan is agreed.
85
+ This is your mapping of `workflow/flow.md` stages 1–2 (*clarify* + *plan sign-off*). In-app, a manager runs these; over the CLI the manager role collapses onto **you**, so you run the interview and the sign-off directly with the user. Don't write slide JSX until the plan is agreed.
64
86
 
65
87
  - **Read scope from the wording**, don't ask redundantly: single slide ("make a slide about X"), small set ("add three slides on Y"), or whole deck ("a deck for Friday"). Only ask "one slide, a small set, or a full deck?" when truly ambiguous.
66
- - **Interview just enough** to pin: audience/goal, the content and its sources (none / pasted / local files / existing deck / web research), the **output format** (push into PowerPoint, `.pptx` file, HTML preview, or a mix), and the slide outline (each slide's role + a layout *job* like cover/agenda/section/quote/closing/body — the concrete brand layout is chosen later against the bundle).
67
- - **Replay and get sign-off.** Single slides / tiny sets → a compact in-chat plan. Decks → persist `decks/<slug>/plan.md` (content direction, narrative red thread, sources, per-slide role + layout job — *not* visual shape, *not* brand specifics). A valid existing `decks/<slug>/plan.md` counts as approved; restate what you're building.
88
+ - **Interview just enough** to pin: audience/goal, the content and its sources (none / pasted / local files / existing deck / web research), and the slide outline (each slide's role + a layout *job* like cover/agenda/section/quote/closing/body — the concrete brand layout is chosen later against the bundle).
89
+ - **Lock the output target — it decides your deliver command.** Into the open PowerPoint (`slidemind push`), or a `.pptx` file (`slidemind build-pptx`) — or an HTML preview / a mix. Infer it when the wording is clear ("add a slide to this deck" → push; "make me a deck I can send around" → a file) and ask only when genuinely ambiguous — but **always confirm the concrete target before delivering** (which window, or which output path).
90
+ - **Replay and get sign-off.** Single slides / tiny sets → a compact in-chat plan (no gate). Decks → persist `decks/<slug>/plan.md` (content direction, narrative red thread, sources, per-slide role + layout job — *not* visual shape, *not* brand specifics), then run `slidemind plan <deck>`: it opens the plan in a markdown editor with a live rendered preview; the user edits `plan.md` directly and/or leaves overall feedback, and it **blocks until the user decides** — give the shell call a **generous timeout** (the gate waits up to 30 min; if your harness kills the call early, just re-run it — the user's open tab reconnects). Outcomes: `DECISION: approved` → proceed to author; `DECISION: comments` → apply the feedback to `plan.md` and **re-run the gate in the same turn** — after a comments round the user's tab sits on a waiting spinner that only the next `slidemind plan` run releases, so never end your turn, never claim to be "polling", and never send the user back to the browser between rounds (that deadlocks: the tab waits for you while you wait for the tab); `DECISION: pending` → the gate timed out with no answer — not approval, not rejection: don't author; wrap up telling the user the plan still awaits their sign-off and re-run `slidemind plan <deck>` on their go-ahead. Loop until approved. A `plan.md` **approved in a prior gate round and unchanged since** counts as approved (skip straight to authoring); any new or revised plan must pass the gate. When the gate reports the user edited `plan.md` directly, re-read it — the edited text *is* the approved plan; author from it.
68
91
 
69
- Keep planning about intent and content. Don't materialize the bundle or read brand/layout/composition detail until create/edit.
92
+ Keep planning about intent and content. The bundle is already materialized by `slidemind ready`, so `design.md` is there if you need to sanity-check feasibility — but **don't dive into brand/layout/composition detail until create/edit.**
70
93
 
71
94
  ## The create flow
72
95
 
73
- 1. **Choose the host** (gate above) → `presentation_id`.
74
- 2. **Materialize the bundle.** `slidemind download-bundle <deck> --to <presId>` downloads the active corporate design and binds the deck to it. The bundle dir is keyed by the deck's `.bundle-ref.json` → `${XDG_CACHE_HOME:-~/.cache}/slidemind/bundles/<presFP>/`. It contains:
75
- - `design.md` — brand rules + authoring contract pointers + the `### Brand Image Sources` block (the brand source of truth — **read it**).
76
- - `corporate-design.css`, `layouts/*.jsx`, `layouts/layouts.css`, `assets/`, `samples/` (the brand's own reference slides), `engines.json`.
77
- - `workflow/` — the add-in-owned authoring craft: `create.md`, `edit.md`, `composition.md`, `layouts.md`, `authoring.md`, `build-and-export.md`.
78
- 3. **Study brand samples (before composing).** The materialized bundle's `samples/` dir holds the brand's own reference slides. If it's non-empty, pick **3 at random** and **Read** each (the Read tool renders images) *before* writing any JSX — this is the local-harness stand-in for the in-app persona's reference thumbnails, and it is what keeps a deck looking on-brand rather than merely compliant. Study them for whitespace rhythm, shape density, hierarchy, accent use, and layering, then compose in that spirit (never copy a sample 1:1). This is `composition.md`'s samples discipline; skip only when `samples/` is empty.
79
- 4. **Read, then author.** Read the four create-stage references together — `workflow/create.md` (the procedure), `workflow/composition.md` (the composition baseline), `workflow/layouts.md` (palette + working area), and `workflow/authoring.md` (the substrate rules) — plus the deck's `design.md` and the specific `layouts/*.jsx` the plan uses. (That is the read set `workflow/create.md` → Context loading prescribes; follow it as written.) Then write `decks/<slug>/slides/NN-<topic>.jsx` — zero-padded numeric prefix from the first file on (play order is filename order here; see the slide-file row in the command mapping), one default export per slide, composing one bundle layout (Mode A) or a blank-content layout with freeform children (Mode B), exactly as those docs prescribe.
80
- 5. **Imagery from the engine.** Per the `### Brand Image Sources` block in `design.md`, search the brand engine and place results. The engine search/reuse mechanics live in **`slidemind-search`** — use it to find and fetch imagery; the create-only icon-recolour detail is in *Recolouring engine icons* below. To pull in an **existing whole slide** (not just an image), use `slidemind-search`'s `add-slide` — it folds the slide into `decks/<slug>/slides/` as a native `.pptx` that coexists with your JSX in play order and survives re-push.
81
- 6. **Look at your own draft first (you, the agent).** This is `see_draft` in `workflow/build-and-export.md` — the agent's pre-check, *before* any human sees the deck. The local-harness port is `slidemind view-draft <deck>` (MCP `slidemind_view_draft({ deck_path })`): it renders each authored `slides/*.jsx` to a per-slide PNG and hands the images back to you — **nothing is pushed, no `.pptx` is written, no review gate opens**. Read every image the way the audience will, fix anything visibly wrong **in the JSX** (re-express, never delete), and view again until each slide is sound. One round usually suffices. It runs locally against the materialized bundle, so it needs no awake pane and no open host once the bundle has been downloaded once. Two faithful limits to know: a slide on a **purpose-built (Mode A) layout** (cover/divider/agenda) and a **reused native `.pptx`** slide have no freeform region to capture, so they come back as a status line, not an image — judge those at the full-deck `review`/`build` step below. Do this self-check before the human review gate; don't push a draft you haven't looked at.
82
- 7. **Preview review, then push.** This is `build_and_push` in `workflow/build-and-export.md`, including its preview review gate — the local harness has a native port: before the FIRST export of new slides, run `slidemind review <deck>`. It builds the HTML preview, opens it in the browser with a spatial comment overlay, and **blocks until the user decides** (host-free — no open PowerPoint needed for the gate). The command then prints its verdict to stdout:
83
- - `DECISION: approved` → proceed to the export the user actually asked for: `slidemind push <deck>` (into PowerPoint) or `slidemind build-pptx <deck>` (to a file).
84
- - `DECISION: comments` → the user left spatially-anchored notes, each citing a `slides/<file>.jsx:line:col`, the source line, and the click position (plus a readonly-layout note where the click landed on a layout slot). **Edit the cited files in place at the given line**, then **re-run `slidemind review <deck>`** — the prior round shows as read-only ghost pins so the user can confirm each note was addressed. Loop until approved. Nothing is exported on a comments round.
85
-
86
- `slidemind review` is the only step that pauses; `push`/`build-pptx` never pause — they render pane-free (local capture + server-side assembly, with live per-slide progress). One approval covers the task: push follow-up fixes without re-running review unless the user wants another look. If several presentations are open, confirm **which one to push into** first (it can differ from the CD source). After approval, run the push without asking; it works while PowerPoint is backgrounded, and the CLI itself waits + retries if the pane is needed (see the precondition gate). If a push still times out, the rendered `.pptx` is saved next to the deck — re-run `push` after the user clicks the pane, without rebuilding.
87
- 8. **Sanity pass.** Run the checks in `workflow/create.md` before reporting done.
96
+ `slidemind ready` already resolved the design source and materialized its bundle; the deck was bound to it by `slidemind ready <deck>` (continuing) or by `slidemind new <slug>`'s auto-bind (new work). From here:
97
+
98
+ 1. **Study brand samples (before composing).** The materialized bundle's `samples/` dir holds the brand's own reference slides. If it's non-empty, pick **3 at random** and **Read** each (the Read tool renders images) *before* writing any JSX — this is the local-harness stand-in for the in-app persona's reference thumbnails, and it is what keeps a deck looking on-brand rather than merely compliant. Study them for whitespace rhythm, shape density, hierarchy, accent use, and layering, then compose in that spirit (never copy a sample 1:1). This is `composition.md`'s samples discipline; skip only when `samples/` is empty.
99
+ 2. **Read, then author.** Read the create-stage references together — `workflow/create.md` (the procedure), `workflow/composition.md` (the composition baseline), `workflow/layouts.md` (palette + working area), and `workflow/authoring.md` (the substrate rules) — plus the deck's `design.md` and the specific `layouts/*.jsx` the plan uses. (That is the read set `workflow/create.md` → Context loading prescribes; follow it as written — `workflow/flow.md` you already read after `ready`.) Then write `decks/<slug>/slides/NN-<topic>.jsx` — zero-padded numeric prefix from the first file on (play order is filename order here; see the slide-file row in the command mapping), one default export per slide, composing one bundle layout (Mode A) or a blank-content layout with freeform children (Mode B), exactly as those docs prescribe.
100
+ 3. **Imagery from the engine.** Per the `### Brand Image Sources` block in `design.md`, search the brand engine and place results. The engine search/reuse mechanics live in **`slidemind-search`** — use it to find and fetch imagery; the create-only icon-recolour detail is in *Recolouring engine icons* below. To pull in an **existing whole slide** (not just an image), use `slidemind-search`'s `add-slide` — it folds the slide into `decks/<slug>/slides/` as a native `.pptx` that coexists with your JSX in play order and survives re-push.
101
+ 4. **Look at your own draft first (you, the agent).** This is the **draft check** in `workflow/build-and-export.md` — your pre-check, *before* any human sees the deck. Run `slidemind view-draft <deck>`: it renders each authored `slides/*.jsx` to a per-slide PNG and hands the images back to you — **nothing is pushed, no `.pptx` is written, no review gate opens**. Read every image the way the audience will, fix anything visibly wrong **in the JSX** (re-express, never delete), and view again until each slide is sound. One round usually suffices. It runs locally against the materialized bundle, so it needs no awake pane and no open host once the bundle has been downloaded once. Two faithful limits to know: a slide on a **purpose-built (Mode A) layout** (cover/divider/agenda) and a **reused native `.pptx`** slide have no freeform region to capture, so they come back as a status line, not an image — judge those at the full-deck `review`/`build` step below. Do this self-check before the human review gate; don't push a draft you haven't looked at.
102
+ 5. **The review gate — the moment the deck builds clean.** This is the **review gate** in `workflow/build-and-export.md`; the CLI's gate command is `slidemind review <deck>`. Run it the instant the authored set builds clean — before any deliver, without asking whether the user wants a review. It builds the HTML preview first (the same lint the render enforces, so a gate that *opens* is a clean build; while lint errors remain it exits non-zero — fix and re-run), then opens the browser with a spatial comment overlay and **blocks until the user decides** (host-free — no open PowerPoint needed for the gate). **Blocking is the point: give the shell call a generous timeout (the gate waits up to 30 min) and let it sit — a long quiet wait means the user is reviewing, not that something hung. Never cancel it; if your harness kills the call early, just re-run it (the user's open tab reconnects).** The verdict prints to stdout:
103
+ - `DECISION: approved` → proceed to the deliver the user chose at intake: `slidemind push <deck>` (into PowerPoint) or `slidemind build-pptx <deck>` (to a file).
104
+ - `DECISION: comments` → the user left spatially-anchored notes, each citing a `slides/<file>.jsx:line:col`, the source line, and the click position (plus a readonly-layout note where the click landed on a layout slot). **Edit the cited files in place at the given line and re-run `slidemind review <deck>` in the same turn** — after a comments round the user's tab waits for the next round, so never end your turn, never claim to be "polling", and never send the user back to the browser between rounds. The prior round shows as read-only ghost pins so the user can confirm each note was addressed. Loop until approved. Nothing is exported on a comments round.
105
+ - `DECISION: pending` → the gate timed out with no answer (the user stepped away). Not approval, not rejection — **do not deliver**. Wrap up your turn: tell the user the preview is still waiting for their review and that on their go-ahead you'll re-run `slidemind review <deck>` (their tab reconnects).
106
+
107
+ `slidemind review` is the only step that pauses; `push`/`build-pptx` never pause — they render pane-free (local capture + server-side assembly, with live per-slide progress). **CLI exports happen out of the user's sight, so the flow invariant — *the user sees every change before the task is done* — makes re-review mandatory here: every deliver is preceded by an approved review of exactly what it delivers. After any later slide change, the deck re-enters `slidemind review` before it can be pushed or exported again — never deliver an unreviewed change.** If several presentations are open, confirm **which one to push into** first (it can differ from the design source `slidemind ready` locked in). After approval, run the push without asking; it works while PowerPoint is backgrounded, and the CLI itself waits + retries if the pane is needed (see *First step* above). If a push still times out, the rendered `.pptx` is saved next to the deck — re-run `push` after the user clicks the pane, without rebuilding.
108
+
109
+ **On a clean approve + deliver, the task is done.** Report what landed (slide count + target) and stop — no sanity pass, no re-verification. The visual QA already happened at the draft check (step 4) and the user signed off at the review gate.
88
110
 
89
111
  ## Recolouring engine icons (create-authoring specifics)
90
112
 
91
- Finding and fetching engine imagery is `slidemind-search`'s job (`slidemind_search_engine` → `slidemind_download_result`). What follows is **create-only**: how to colour a fetched icon so it reads on-brand in your JSX, honoured in both the `slidemind build` preview and the render.
113
+ Finding and fetching engine imagery is `slidemind-search`'s job (`slidemind search` → `slidemind download-result`). What follows is **create-only**: how to colour a fetched icon so it reads on-brand in your JSX, honoured in both the `slidemind build` preview and the render.
92
114
 
93
- Engine results land as files referenced with `<img src="./assets/<file>">`. The bundle's `workflow/*.md` are written for the in-app render; these two facts are specific to the local harness:
115
+ Engine results land as files referenced with `<img src="./assets/<file>">`. These facts are specific to the local harness (the bundle's `workflow/*.md` stay harness-neutral):
94
116
 
95
- - **Never open the SVG to find out whether it recolours.** `slidemind_download_result` returns a `recolor` descriptor — `{ recolorable, mode, applied, note }`, where `mode` is `currentColor`, `mono`, `multicolor`, or `raster`. Read it; that *is* the answer.
117
+ - **Never open the SVG to find out whether it recolours.** `slidemind download-result` prints a `recolor` descriptor for each asset — `{ recolorable, mode, applied, note }`, where `mode` is `currentColor`, `mono`, `multicolor`, or `raster`. Read it; that *is* the answer.
96
118
  - **Two ways to colour an icon, both honoured in the `slidemind build` preview *and* the render:**
97
- - **Bake it in (prefer this):** pass `icon_color` — a hex you resolve from a token in the bundle's `corporate-design.css` — to `slidemind_download_result`. Works for any `recolorable` glyph and the colour is in the saved file, so preview and render always agree.
119
+ - **Bake it in (prefer this):** pass `--icon-color <hex>` — a hex you resolve from a token in the bundle's `corporate-design.css` — to `slidemind download-result`. Works for any `recolorable` glyph and the colour is in the saved file, so preview and render always agree.
98
120
  - **Tint via CSS:** set `color` to a token on the `<img>`. This works only for `mode: "currentColor"` icons (the preview inlines the SVG so `color` resolves, and the render substitutes `currentColor`). A `mono` icon will not respond to CSS colour — bake it instead.
99
- - **Batch the fetch.** Pull every icon a slide needs in one call via `selections: [{ selection, icon_color }, …]` — the downloads run concurrently. Don't call `slidemind_download_result` once per icon.
121
+ - **Batch the fetch.** Pull every icon a slide needs in one call — `slidemind download-result --search <id> --pick <n,n,…> --deck <deck> --to <presId> [--icon-color <hex,hex,…>]` (one colour applies to all picks, or give one per pick) — the downloads run concurrently. Don't run `download-result` once per icon.
100
122
 
101
- ## Command mapping (CLI ⇄ the bundle's `workflow/*.md`)
123
+ ## Command mapping (the workflow vocabulary ⇄ your CLI)
102
124
 
103
- The bundle's `workflow/*.md` are written for the in-app design agent and name **its** tools. You are the local harness — translate as you read:
125
+ The bundle's `workflow/*.md` speak the harness-neutral verbs defined in `workflow/flow.md` → Vocabulary. You are the local harness — this is your mapping:
104
126
 
105
- | In `workflow/*.md` (in-app agent) | Your equivalent (local harness) |
127
+ | Verb (`workflow/flow.md`) | Your equivalent (local harness) |
106
128
  |---|---|
107
- | `build_and_push` | `slidemind push <deck>` (into the open PowerPoint) · `slidemind build-pptx <deck>` (to a `.pptx` file) — both render server-side via the bridge |
108
- | `read_presentation_context` (read the live deck) | `slidemind read [presId] [--mode summary\|raw]` · MCP `slidemind_read_presentation({ presentation_id?, mode? })` — pull the current content of an open presentation (`summary` = per-slide outline; `raw` = each slide's plain text) to inspect what's there before editing. Plain text, not authoring markup |
109
- | `engine_search` / `engine_add` / `insert_image` | **`slidemind-search`** owns the engine search + reuse mechanics (`slidemind_search_engine` → `slidemind_download_result`, plus whole-slide reuse via `add-slide`). For placing a fetched icon in your JSX, pass `icon_color` / batch with `selections: [{ selection, icon_color }, …]` and colour per *Recolouring engine icons* below |
110
- | writing `slides/<topic>.jsx` in the chat workspace — unprefixed kebab-case names; play order = the ordered list passed to `build_and_push` | write `decks/<slug>/slides/NN-<topic>.jsx` on disk with a **zero-padded numeric prefix** (`01-cover.jsx`, `02-agenda.jsx`, …) — over the CLI play order is **numeric-aware filename order**; there is no ordered-list channel, so reordering = renaming files. The bundle's "don't pad with index prefixes" rule is in-app-only; here it inverts |
111
- | reading workspace files (`design.md`, `layouts/`, `workflow/*`) | read them from the materialized bundle dir (`<bundle>/…`) and your `decks/<slug>/` |
112
- | reference-slide thumbnails injected at `add_slide` (in-app persona) | **Read** 3 random images from the materialized bundle's `samples/` dir — the Read tool renders them (see *The create flow* step 3) |
113
- | `present_plan_for_review` (manager-owned) | **you** run intake → plan with the user (above); persist `decks/<slug>/plan.md` for decks |
114
- | `see_draft` (agent looks at its OWN draft before pushing) | `slidemind view-draft <deck>` · MCP `slidemind_view_draft({ deck_path })` — renders each `slides/*.jsx` to a per-slide PNG and returns the images to **you**; **no push, no `.pptx`, no review gate**. Look, fix the JSX, view again. Host-free once the bundle is materialized. Freeform slides only — purpose-built (Mode A) and reused native `.pptx` slides report as a status line (judge those at `review`/`build`). This is the agent self-check; `slidemind review` is the *human* gate |
115
- | the `build_and_push` **preview review gate** (pause on rendered previews → approve / per-element comments) | `slidemind review <deck>` — a native port of the same gate: serves the HTML preview with a spatial comment overlay and **blocks until the user decides**, then prints `DECISION: approved` or `DECISION: comments` (each comment cited to `slides/<file>.jsx:line:col`). On approve → run the export (`slidemind push` / `build-pptx`); on comments → edit the cited files and re-run `slidemind review` (prior round shows as ghost pins). One approval covers the task. `push`/`build-pptx` never pause; only `review` does. |
116
-
117
- Everything else in `workflow/*.md` — the composition craft, the substrate/authoring rules, the layout discovery and slot/working-area rules, the sanity bar — applies to you unchanged.
129
+ | (session setup — a CLI-only stage before the spine) | `slidemind ready [deck]` — the one-shot session start: connection ladder + open-design resolution + bundle materialize + deck bind. **Run it first, every session** (see *First step* above). `slidemind download-bundle` is the lower-level materialize-only command `ready` now covers — you rarely call it directly |
130
+ | **track the stages** | your harness's task tracker — explicitly create the stage todo list before your first command and keep it current (see *Create a todo list* above) |
131
+ | **clarify** / **plan sign-off** | intake stays in chat with the user (above); for decks, persist `decks/<slug>/plan.md`, then run `slidemind plan <deck>` — the same blocking `DECISION:` gate contract as `slidemind review`, on the plan (markdown editor + live preview + overall feedback; loop until approved) |
132
+ | **read** / **list** the workspace | read the files from the materialized bundle dir (`<bundle>/…`) and your `decks/<slug>/` |
133
+ | **create / update a slide file** | write `decks/<slug>/slides/NN-<topic>.jsx` on disk with a **zero-padded numeric prefix** (`01-cover.jsx`, `02-agenda.jsx`, …) — over the CLI, "the ordered set you hand to build & push" is expressed as **numeric-aware filename order**; there is no ordered-list channel, so reordering = renaming files |
134
+ | brand reference samples (studied before composing) | **Read** 3 random images from the materialized bundle's `samples/` dir — the Read tool renders them (see *The create flow* step 1) |
135
+ | **draft check** | `slidemind view-draft <deck>` — renders each `slides/*.jsx` to a per-slide PNG and returns the images to **you**; **no push, no `.pptx`, no review gate**. Look, fix the JSX, view again. Host-free once the bundle is materialized. Freeform slides only — purpose-built (Mode A) and reused native `.pptx` slides report as a status line (judge those at `review`/`build`). This is your self-check; `slidemind review` is the *human* gate |
136
+ | **build & push** | `slidemind push <deck>` (into the open PowerPoint) · `slidemind build-pptx <deck>` (to a `.pptx` file) — deliver whichever target was locked at intake; both render server-side via the bridge, and for a bound deck the render is pane-free (`build-pptx` needs no PowerPoint window at all) |
137
+ | **the review gate** | `slidemind review <deck>` — builds the HTML preview (lint-clean or it doesn't open), serves it with a spatial comment overlay and **blocks until the user decides**, then prints `DECISION: approved` or `DECISION: comments` (each comment cited to `slides/<file>.jsx:line:col`). On approve → deliver (`slidemind push` / `build-pptx`); on comments → edit the cited files and re-run `slidemind review` (prior round shows as ghost pins). CLI delivers happen out of the user's sight, so **every deliver follows an approved review of what it delivers — re-run `review` after any slide change**. `push`/`build-pptx` never pause; only `review` does. |
138
+ | **inspect the deck** | `slidemind read [presId] [--mode summary\|raw]` — pull the current content of an open presentation (`summary` = per-slide outline; `raw` = each slide's plain text) to inspect what's there before editing. Plain text, not authoring markup |
139
+ | **engine search / fetch** | **`slidemind-search`** owns the engine search + reuse mechanics (`slidemind search` → `slidemind download-result`, plus whole-slide reuse via `add-slide`). For placing a fetched icon in your JSX, pass `--icon-color` / batch with `--pick <n,n,…>` and colour per *Recolouring engine icons* below |
140
+ | **see** a live slide | no CLI analog — once delivered, the user is looking at the result; your visual authority runs at the draft check and the review gate instead |
141
+
142
+ Everything else in `workflow/*.md` — the composition craft, the substrate/authoring rules, the layout discovery and slot/working-area rules, the visual quality bar (applied at the draft check) — applies to you unchanged.
118
143
 
119
144
  ## The brand and the workflow both live in the bundle, not here
120
145
 
@@ -122,7 +147,7 @@ Do not restate brand values (colour, type scale, spacing, layout names, accent d
122
147
 
123
148
  ## Failure modes the render lint can't catch
124
149
 
125
- Render-time lint rejects contract violations (unsupported CSS, bad imports, remote `<img>` URLs — the add-in's capability-table engine; `slidemind build` runs the same engine locally from the bundle). It can't catch content-shaped failures; check for these in the sanity pass:
150
+ Render-time lint rejects contract violations (unsupported CSS, bad imports, remote `<img>` URLs — the add-in's capability-table engine; `slidemind build` runs the same engine locally from the bundle). It can't catch content-shaped failures; check for these **at the draft check** (step 4, before the review gate) — not after delivery:
126
151
 
127
152
  - Layout-default / placeholder text leaking through an unfilled prop.
128
153
  - A bullet list standing in for a structured idea (process, comparison, timeline).
@@ -7,27 +7,27 @@ description: Discover, search, and reuse content from the active corporate desig
7
7
 
8
8
  This skill is **thin workflow glue for the local harness**. The capability it drives — engine discovery, image/slide search, and slide reuse — runs on the **slidemind PowerPoint add-in**: the engines, the corporate design they belong to, and the search/extraction execution all live there and reach you over the add-in's cloud relay. The **craft** of using it well — how to discover engines, choose content-vs-visual search, pick a result, and reuse a slide responsibly — is authored once by the add-in and served on the materialized bundle as `workflow/search.md`, **byte-identical** to what the in-app design agent reads.
9
9
 
10
- So this file owns only what is genuinely CLI-specific: the **host precondition**, the **discover → search → pick → reuse** loop, the **reuse targets** (insert live vs fold into a deck), and the **command mapping** that translates the add-in's in-app verb names (used in `workflow/search.md`) into your `slidemind` commands and MCP tools. **Read `workflow/search.md` from the bundle; never restate the craft here.**
10
+ So this file owns only what is genuinely CLI-specific: the **host precondition**, the **discover → search → pick → reuse** loop, the **reuse targets** (insert live vs fold into a deck), and the **command mapping** that translates `workflow/search.md`'s harness-neutral verbs into your `slidemind` CLI commands. **Read `workflow/search.md` from the bundle; never restate the craft here.**
11
+
12
+ **slidemind is a CLI you drive directly.** Run `slidemind <command>` in your shell — the same way you'd run `git` or `npm`. There is no separate tool layer to go through; every step below is a real command you type.
11
13
 
12
14
  ## Bootstrap (set yourself up — don't make the user do it)
13
15
 
14
- This skill drives the `slidemind` CLI + its MCP server (`slidemind_list_open_presentations`, `slidemind_list_engines`, `slidemind_search_engine`, `slidemind_view_slide`, `slidemind_insert_slide`, `slidemind_add_slide_to_deck`, `slidemind_download_result`). The CLI reaches PowerPoint through the add-in's **cloud relay** — it doesn't run any local server. Patch what's missing yourself; the **pairing** step needs the user once (they hold the add-in's identity):
16
+ **The first step of a search session is `slidemind ready --connect-only`** (see *Precondition gate* below). It drives the `slidemind` CLI, which reaches PowerPoint through the add-in's **cloud relay** — no local server. Patch a missing CLI yourself; **pairing** needs the user once (they hold the add-in's identity):
15
17
 
16
- - **CLI missing** (`slidemind` not on `PATH`, or the `slidemind_*` MCP tools absent): `npm install -g slidemind`, then `slidemind init --for <claude|codex|opencode|all>` (registers the MCP server + (re)deploys this skill). The harness may need a restart for the `slidemind_*` tools to appear.
17
- - **Not paired** (a command says *slidemind is not paired*): the one step you can't do for the user. Tell them: in the slidemind add-in open **Settings → General → Connect CLI**, press **Pair**, and run the shown one-time `slidemind pair <code>` command in this terminal (the code expires in ~10 min — re-press **Pair** for a fresh one). It's one-time per environment; `slidemind whoami` lists every paired environment.
18
- - **Restart the add-in once after pairing** — the wizard never says this. If, right after pairing, `slidemind presentations` still doesn't list the window even though PowerPoint is open with the add-in and a corporate design active, ask the user to **restart the add-in** (close + reopen the slidemind task pane; if it still doesn't appear, reopen PowerPoint) so the freshly-paired pane registers on the relay. Then retry.
18
+ - **CLI missing** (`slidemind` not on `PATH`): `npm install -g slidemind`, then `slidemind init --for <claude|codex|opencode|all>` ((re)deploys this skill).
19
+ - **Not paired** (`ready` blocks with `not_paired`, or a command says *slidemind is not paired*): the one step you can't do for the user. Tell them: in the slidemind add-in open **Settings → General → Connect CLI**, press **Pair**, and run the shown one-time `slidemind pair <code>` command in this terminal (the code expires in ~10 min — re-press **Pair** for a fresh one). `slidemind whoami` lists every paired environment.
19
20
 
20
- This is the same bootstrap as `slidemind-create-slides` (whose **Pairing the CLI with the add-in** section has the full step-by-step + triage table); if you set it up there it's already set up here.
21
+ This is the same setup as `slidemind-create-slides`, whose **Pairing the CLI with the add-in** section carries the full step-by-step (including the restart-the-add-in-once nudge after a fresh pairing). If you set it up there it's already set up here.
21
22
 
22
23
  ## Precondition gate (check this first, every time)
23
24
 
24
- Engine search and slide reuse are **pane-touching, host-required** operations — the same gate `slidemind-create-slides` describes. Without an open PowerPoint host with the slidemind add-in loaded and an active corporate design, there are no engines to query and nowhere to insert.
25
-
26
- 1. Run `slidemind presentations` (or MCP `slidemind_list_open_presentations`).
27
- 2. **≥1 registered → you're set.** The engine catalog is **per-user, not bound to a window**, so search and discovery attach to **any** connected window automatically. **Never ask the user which window to search with**, and don't pass `--to`/`presentation_id` to search just to disambiguate — leave it off and let the CLI grab one. (A window only matters when you *insert a slide live*, and even then it's simply the window the search already ran on — see Reuse.)
28
- 3. **None registered → stop.** Tell the user: *open PowerPoint, load the slidemind add-in, and pick or create a corporate design, then retry.*
25
+ Engine search and slide reuse are **host-required** operations — without an open PowerPoint host with the slidemind add-in loaded and an active corporate design, there are no engines to query and nowhere to insert. Check the connection in one call:
29
26
 
30
- > **Empty list vs. not paired — different fixes.** An *empty* registry with no PowerPoint connected means open it / enable Connect CLI. A *not paired* error means this machine has no session — pair once via **"Connect CLI"** (see Bootstrap). An *empty* registry **while** PowerPoint is open with the add-in **and** this machine is already paired usually means a just-paired pane that never registered — ask the user to **restart the add-in** (see Bootstrap), then retry. Three different problems; don't conflate them.
27
+ 1. Run `slidemind ready --connect-only`. It walks the connection ladder (pairing → reachable backend → CLI version → an open window) but does **not** resolve a design or download a bundle — search doesn't need one.
28
+ - **Exit 0 → you're set.** Proceed to `slidemind ls engines` (the live catalog is authoritative — the first real-work step).
29
+ - **Non-zero →** the CLI names exactly one blocker and one `nextAction`; relay it (pair / open PowerPoint / click the pane / run `slidemind update`). The CLI owns the remediation text — don't restate it.
30
+ 2. **Never pick a window for discovery.** The engine catalog is **per-user, not bound to a window**, so search and discovery attach to **any** connected window automatically. **Never ask the user which window to search with**, and don't pass `--to` to search just to disambiguate — leave it off and let the CLI grab one. (A window only matters when you *insert a slide live*, and even then it's simply the window the search already ran on — see Reuse.)
31
31
 
32
32
  The pane-touching ops here (`search`, `view_slide`, `insert-slide`, `download-result`) wait for the pane themselves: the CLI waits up to ~2 min, prints one *"click the slidemind pane"* line when user help is genuinely needed, and retries safely. Relay that line once and keep waiting — don't re-plan or babysit.
33
33
 
@@ -35,41 +35,41 @@ The pane-touching ops here (`search`, `view_slide`, `insert-slide`, `download-re
35
35
 
36
36
  Follow `workflow/search.md` for the discipline; this is the CLI shape of its loop.
37
37
 
38
- 1. **Discover engines — never guess an id.** Run `slidemind ls engines` (MCP `slidemind_list_engines`) and read the catalog before searching. Filter to what you need with `--type <collection|search>` and `--subtype <image|slide|template|content>` (e.g. `slidemind ls engines --type search --subtype slide` for slide libraries). The catalog is **per-user, not per-presentation** — there is no presId to scope; spanning every paired environment, each engine is tagged with its `env`. (`--to`/`presentation_id` is accepted for symmetry with the other commands but ignored — it does not narrow the catalog.) Pick an engine **id** from the list — do not invent one.
38
+ 1. **Discover engines — never guess an id.** Run `slidemind ls engines` and read the catalog before searching. Filter to what you need with `--type <collection|search>` and `--subtype <image|slide|template|content>` (e.g. `slidemind ls engines --type search --subtype slide` for slide libraries). The catalog is **per-user, not per-presentation** — there is no presId to scope; spanning every paired environment, each engine is tagged with its `env`. (`--to` is accepted for symmetry with the other commands but ignored — it does not narrow the catalog.) Pick an engine **id** from the list — do not invent one.
39
39
  2. **Choose the engine + intent.** Slide engines (`subtype slide`) support two intents: **content** (the slide's text is the signal — title, body, tables, notes) and **visual** (the slide image is the signal). Image/icon engines (`subtype image`) are **visual-only**. Match the intent to the ask: "a slide that says X" / "covers topic Y" → `--intent content`; "a slide that looks like X" / brand imagery → `--intent visual`. `--intent auto` lets the engine decide.
40
- 3. **Search — no window to choose.** `slidemind search "<query>" --engine <id> --intent <auto|content|visual> [--top N]` (MCP `slidemind_search_engine({ query, engine_id?, intent?, top? })` — `presentation_id` is **optional; omit it**). Search attaches to any connected window itself and returns a `searchId` plus numbered results, and it tells you **which window it ran on** (the CLI prints it; the MCP tool echoes it back as `presentation_id`). **Thread that returned `presentation_id` into every follow-up** (view / insert / add-slide): the `searchId` is bound to that window, so a follow-up aimed at a different window won't find it.
41
- 4. **Read / view, then pick.** For **content** results, read the per-slide **text + score** the search prints — that is the on-the-wire signal; you usually don't need the picture. For **visual** results, scan the numbered thumbnail list; pull a single result's image on demand with `slidemind_view_slide({ presentation_id, search_id, selection })` (or `slidemind search … --json` for the structured payload). Pick by **selection number(s)**.
40
+ 3. **Search — no window to choose.** `slidemind search "<query>" --engine <id> --intent <auto|content|visual> [--top N]` (leave `--to` off — search attaches to any connected window itself). It returns a `searchId` plus numbered results, and prints **which window it ran on** (`searchId N ran on window <presId>`). **Thread that `presId` into every follow-up** as `--to <presId>` (view-slide / insert-slide / add-slide / download-result): the `searchId` is bound to that window, so a follow-up aimed at a different window won't find it.
41
+ 4. **Read / view, then pick.** For **content** results, read the per-slide **text + score** the search prints — that is the on-the-wire signal; you usually don't need the picture. For **visual** results, scan the numbered thumbnail list; pull a single result's image on demand with `slidemind view-slide --search <searchId> --pick <n> --to <presId>` (it writes the preview to a file you can Read), or `slidemind search … --json` for the structured payload. Pick by **selection number(s)**.
42
42
  5. **Reuse.** Insert live or fold into a deck — see the next section.
43
43
 
44
44
  ## Reuse targets — insert live, or fold into a deck
45
45
 
46
46
  A found slide can be reused two ways. Both extract the picked result(s) as native PowerPoint slides — **reuse is JSX-free; reused slides are native `.pptx`, never JSX.**
47
47
 
48
- - **Insert LIVE into an open PowerPoint** — `slidemind insert-slide --search <searchId> --pick <n[,n,…]> --to <searchWindow> [--at <N>]` (MCP `slidemind_insert_slide({ presentation_id, search_id, selections, at? })`), where `<searchWindow>` is the `presentation_id` the search returned. The picked slides land in **that** window (the one the search ran on; at position `--at`, else appended). If the slide must go into a *specific* open window, run the search with `--to <thatWindow>` so the search — and therefore the insert — happen there.
49
- - **Fold into a DECK on disk** — `slidemind add-slide --search <searchId> --pick <n[,n,…]> --deck <deck> --to <searchWindow> [--at <N>]` (MCP `slidemind_add_slide_to_deck({ presentation_id, deck_path, search_id, selections, at? })`), where `<searchWindow>` is the `presentation_id` the search returned — the extraction must run on the window that holds the `searchId`. Each picked result is written as a native one-slide file into `decks/<slug>/slides/NN-reused-*.pptx`, in play order; no live window is changed. Use this when the reused slide should become **part of a deck the user keeps and re-renders.**
48
+ - **Insert LIVE into an open PowerPoint** — `slidemind insert-slide --search <searchId> --pick <n[,n,…]> --to <searchWindow> [--at <N>]`, where `<searchWindow>` is the presId the search returned. The picked slides land in **that** window (the one the search ran on; at position `--at`, else appended). If the slide must go into a *specific* open window, run the search with `--to <thatWindow>` so the search — and therefore the insert — happen there.
49
+ - **Fold into a DECK on disk** — `slidemind add-slide --search <searchId> --pick <n[,n,…]> --deck <deck> --to <searchWindow> [--at <N>]`, where `<searchWindow>` is the presId the search returned — the extraction must run on the window that holds the `searchId`. Each picked result is written as a native one-slide file into `decks/<slug>/slides/NN-reused-*.pptx`, in play order; no live window is changed. Use this when the reused slide should become **part of a deck the user keeps and re-renders.**
50
50
 
51
51
  > **The durable rule:** a slide folded into a deck with `add-slide` is **deck source-of-truth**. The render pipeline splices native `slides/*.pptx` into the deck **by play-order filename**, alongside any authored `.jsx`, so a reused slide **survives every `build-pptx` and `push` re-render** — it is never lost on re-push. Reorder it the same way you reorder JSX: rename its numeric prefix.
52
52
 
53
53
  > **Building a `.pptx` file from found slides → one combined deck, always.** When the user wants the reused slides as a **`.pptx` file** (rather than a live insert), collect **every** picked slide into **one** deck and render **one** file — never one `.pptx` per slide and never a deck per slide. Fold all picks into the same deck — pass every selection in a single `add-slide` call (`--pick n1,n2,…`), repeating only to cover picks that came from different `searchId`s (always the same `--deck`) — then run `slidemind build-pptx <deck>` once. The render splices every native `slides/*.pptx` into a **single `decks/<slug>/<slug>.pptx`** in play-order, so all the found slides land in one file. That combined `.pptx` is the deliverable; hand back its path. (Need new authored slides interleaved with the reused ones in that same file? That's still one deck — hand off to `slidemind-create-slides` to add the JSX, then `build-pptx` the whole deck once.)
54
54
 
55
- For brand **imagery** (icons/images, not whole slides), the reuse step is `slidemind_download_result` — it writes the asset into the deck's `assets/`. That mechanism (including the icon-recolor descriptor) is documented where it's used, in `slidemind-create-slides`.
55
+ For brand **imagery** (icons/images, not whole slides), the reuse step is `slidemind download-result` — it writes the asset into the deck's `assets/`. That mechanism (including the icon-recolor descriptor and `--icon-color`) is documented where it's used, in `slidemind-create-slides`.
56
56
 
57
57
  ## Working with slidemind-create-slides
58
58
 
59
59
  These two skills compose. When the user is **authoring** a deck (that's `slidemind-create-slides`) and wants an **existing** slide incorporated, reach for this skill's `add-slide`: it folds the existing slide into the same `decks/<slug>/slides/` directory as the authored JSX. The reused `.pptx` and the authored `.jsx` coexist in play order (numeric filename prefix) and the reused slide is **not lost on re-push**. Hand back to `slidemind-create-slides` for any new content authoring.
60
60
 
61
- ## Command mapping (CLI ⇄ the bundle's `workflow/search.md`)
61
+ ## Command mapping (the search vocabulary ⇄ your CLI)
62
62
 
63
- `workflow/search.md` is written for the in-app design agent and names **its** verbs. You are the local harness — translate as you read:
63
+ `workflow/search.md` speaks harness-neutral verbs (discover engines, search with intent, pick, insert live, fold into a deck, engine fetch). You are the local harness — this is your mapping:
64
64
 
65
- | In `workflow/search.md` (in-app agent) | Your equivalent (local harness) |
65
+ | Verb (`workflow/search.md`) | Your equivalent (local harness) |
66
66
  |---|---|
67
- | `list_engines` | `slidemind ls engines [--type …] [--subtype …]` · MCP `slidemind_list_engines({ type?, subtype? })` — returns the engine catalog (pick an `id`; never guess one). The catalog is backend/user-scoped; `--to`/`presentation_id` is accepted but ignored (informational only). |
68
- | `engine_search` (with `intent`) | `slidemind search "<query>" --engine <id> --intent <auto\|content\|visual> [--top N]` · MCP `slidemind_search_engine({ query, engine_id?, intent?, top? })` — `presentation_id` **optional** (attaches to any window) → a `searchId` + numbered results, **plus the `presentation_id` it ran on** (thread that into the follow-ups below) |
69
- | view a result on demand (the in-app agent has **no** dedicated verb — it reads the search collage) | MCP `slidemind_view_slide({ presentation_id, search_id, selection })` — pull one result's image (`presentation_id` = the window the search returned) · or `slidemind search … --json` for the structured payload. **CLI/MCP-only** capability: there is no in-app `view_result`/`read_slide` tool for engine results. |
70
- | `insert` (reuse a slide → live) | `slidemind insert-slide --search <searchId> --pick <n[,n,…]> --to <searchWindow> [--at N]` · MCP `slidemind_insert_slide({ presentation_id, search_id, selections, at? })` — `presentation_id`/`--to` = the window the search returned; the slide lands there |
71
- | reuse a slide → into a deck (CLI-only) | `slidemind add-slide --search <searchId> --pick <n[,n,…]> --deck <deck> --to <searchWindow> [--at N]` · MCP `slidemind_add_slide_to_deck({ presentation_id, deck_path, search_id, selections, at? })` → writes `decks/<slug>/slides/NN-reused-*.pptx`; `presentation_id`/`--to` = the window the search returned (extraction runs there) |
72
- | `engine_add` / `insert_image` (reuse an image asset) | MCP `slidemind_download_result({ presentation_id, deck_path, search_id, selection })` — writes into `decks/<slug>/assets/` (recolor descriptor + tinting are covered in `slidemind-create-slides`) |
67
+ | **discover engines** ("list what you can reach") | `slidemind ls engines [--type …] [--subtype …]` — returns the engine catalog (pick an `id`; never guess one). The catalog is backend/user-scoped; `--to` is accepted but ignored (informational only). |
68
+ | **engine search** (with `intent`) | `slidemind search "<query>" --engine <id> --intent <auto\|content\|visual> [--top N]` — leave `--to` off (attaches to any window) → a `searchId` + numbered results, **plus the presId it ran on** (thread that in as `--to` on the follow-ups below) |
69
+ | **pull an on-demand thumbnail** for a stored result | `slidemind view-slide --search <searchId> --pick <n> --to <searchWindow>` — writes one result's preview image to a file (`--to` = the window the search returned) · or `slidemind search … --json` for the structured payload. |
70
+ | **insert live** (reuse a slide → the open window) | `slidemind insert-slide --search <searchId> --pick <n[,n,…]> --to <searchWindow> [--at N]` — `--to` = the window the search returned; the slide lands there |
71
+ | **fold into a deck** (reuse a slide → deck source) | `slidemind add-slide --search <searchId> --pick <n[,n,…]> --deck <deck> --to <searchWindow> [--at N]` → writes `decks/<slug>/slides/NN-reused-*.pptx`; `--to` = the window the search returned (extraction runs there) |
72
+ | **engine fetch** (reuse an image asset) | `slidemind download-result --search <searchId> --pick <n[,n,…]> --deck <deck> --to <searchWindow> [--icon-color <hex[,hex,…]>]` — writes into `decks/<slug>/assets/` (recolor descriptor + tinting are covered in `slidemind-create-slides`) |
73
73
 
74
74
  Everything else in `workflow/search.md` — the engine-discovery discipline, content-vs-visual judgement, the picking and reuse craft — applies to you unchanged.
75
75