slidemind 0.3.4 → 0.3.12

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.
@@ -5,51 +5,170 @@ description: Author branded slide decks and individual slides against the active
5
5
 
6
6
  # slidemind-create-slides
7
7
 
8
- This skill is **thin workflow glue for the local harness**. Everything that determines how a deck is authored, styled, and rendered lives in the **slidemind PowerPoint add-in** and reaches you through a **materialized design bundle**:
9
-
10
- - The **brand** — tokens, `corporate-design.css`, the `design.md` brand rules, the closed layout palette, brand assets — is served per corporate design.
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.
8
+ This skill is **thin workflow glue for the local harness**. Everything that determines how a deck is
9
+ authored, styled, and rendered lives in the **slidemind PowerPoint add-in** and reaches you through
10
+ a **materialized design bundle**:
11
+
12
+ - The **brand** — tokens, `corporate-design.css`, the `design.md` brand rules, the closed layout
13
+ palette, brand assets — is served per corporate design.
14
+ - The **authoring workflow craft** — create, edit, composition, layouts, authoring contract,
15
+ build/export — is the add-in's deployment-shipped `workflow/*.md`, served on the same bundle so
16
+ the local harness reads **byte-identical** guidance to the in-app design agent.
12
17
  - The **`.pptx` render** happens server-side in the add-in. There is no local exporter.
13
18
 
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.
19
+ So this file owns only what is genuinely CLI-specific: the **first-step design-bundle gate**, a
20
+ compact **intake/plan**, the **create flow**, and the **command mapping** that translates the
21
+ workflow vocabulary — the harness-neutral verbs defined in the bundle's `workflow/flow.md` and
22
+ spoken throughout `workflow/*.md` — into your `slidemind` CLI commands. Read the workflow + brand
23
+ from the bundle; never restate or duplicate them here.
24
+
25
+ Brand sample slides are private inputs to the add-in's concept generator. They are not authoring
26
+ references and are deliberately not materialized into the local bundle. From the concept pass
27
+ onward, re-read only `decks/<slug>/concepts/concept-slide-NN.png`; when a concept is unavailable,
28
+ fall back to the approved storyboard plus `design.md` and the chosen layout, never to samples.
15
29
 
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.
30
+ **slidemind is a CLI you drive directly.** Run `slidemind <command>` in your shell — the same way
31
+ you'd run `git` or `npm`. There is no separate tool layer to go through; every step below is a real
32
+ command you type.
17
33
 
18
34
  ## Create a todo list (before your first command)
19
35
 
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:
36
+ The moment this skill activates on an authoring task, **create a todo list of the workflow stages**
37
+ in your harness's task tracker — before you run anything — and keep it current: mark each stage done
38
+ as you complete it. This is `workflow/flow.md` → *track the stages*; the list is what keeps the
39
+ later stages (above all the review gate) from being skipped. The stages, as they run over the CLI:
21
40
 
22
41
  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. Concept mockups — `slidemind concepts <deck>`, then rebuild each toward its mockup (a deck authored from an approved plan; see *The create flow* below)
26
- 5. Author the slides
27
- 6. Draft check — `slidemind view-draft`
28
- 7. Review gate — `slidemind review`, the moment the deck builds clean
29
- 8. Deliver — `slidemind push` or `slidemind build-pptx`, whichever target was locked in stage 2
30
-
31
- **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.
32
-
33
- **Concept mockups (stage 4) are a mandatory deck stage, not an optional aid.** After plan sign-off, for a deck authored from an approved plan, you **always** run `slidemind concepts <deck>` and rebuild each `concept-slide-NN.png` toward its target — this is the local-harness equivalent of the in-app manager's *unconditional* concept pass on every full-deck delegation (`generateConceptImages` fires for `approvedPlan && !targetSlideScope`). It degrades benignly: if it returns no mockups (exit 0 — the add-in can't generate them) you author from the storyboards alone, but the *attempt* is not optional. Skip it only where the add-in's `!targetSlideScope` gate would — a single slide, a tiny in-chat set, or a targeted rework of existing slides.
42
+ 2. Clarify with the user — the content **and the output target** (*Intake → plan* below; needs no
43
+ host, so it can run while `ready` executes)
44
+ 3. Plan sign-off — `slidemind plan <deck>` (every from-scratch request — one slide included)
45
+ 4. Concept mockups — `slidemind concepts <deck>`, then immediately inspect every mockup (anything
46
+ authored from an approved plan, a single slide included; see *The create flow* below). **The FILES ON DISK are the
47
+ truth, not the command output you saw.** Generation takes 1–2 minutes and your harness may
48
+ time the command out, showing you only progress lines while the detached process finishes
49
+ writing the PNGs — output that ends mid-progress means TIMED OUT, never "no mockups". The
50
+ moment the command returns (complete or cut off): run `ls decks/<slug>/concepts/`. PNGs
51
+ listed → re-run `slidemind concepts <deck>` once (it returns the full path list instantly for
52
+ already-generated mockups) and Read every file. **Claiming the concepts are missing requires
53
+ double evidence**: `asset-plan.md` may say "no mockups" ONLY when BOTH the re-run's output
54
+ printed zero paths AND `ls decks/<slug>/concepts/` is empty — quote both in the file.
55
+ Authoring a concept-seeded deck without having Read the concept PNGs that exist on disk is the
56
+ single largest fidelity failure this workflow has; nothing about a truncated stdout excuses it.
57
+ **User-provided images** go into this command, classified from the user's words: a sketch or
58
+ mockup to build ("build it like this") → `--concept <file>[@N,M]` (it becomes the mockup for
59
+ those slides, no generation); a look to emulate ("in this style") → `--style <file>[@N,M]`
60
+ (leads the generation; repeatable; `@` omitted = all slides). A photo or logo to place on a slide
61
+ is not a concept input: copy it into `decks/<slug>/assets/` and list it in `asset-plan.md`.
62
+ 5. Source assets — write `decks/<slug>/asset-plan.md` from the concepts, then search + download
63
+ every item in it (*The create flow* steps 2–3). **This stage is not optional and not mergeable
64
+ into authoring**: it is done when every plan item is checked off with a filename or marked
65
+ `(no result)` after its search ran. A deck with concept mockups and an empty `assets/` beyond
66
+ the brand chrome means this stage was skipped, not completed.
67
+ 6. Author the slides
68
+ 7. Draft check — `slidemind view-draft`
69
+ 8. Review gate — `slidemind review`, the moment the deck builds clean
70
+ 9. Deliver — `slidemind push` or `slidemind build-pptx`, whichever target was locked in stage 2
71
+
72
+ **Changing slides that already exist runs a shorter list.** When the deck is on disk and the
73
+ request targets slides in it — "make slide 13 clearer", "rescope 12 and 13", "fix the spacing",
74
+ comments on a delivered deck — the stages are `ready` → edit → `view-draft` → `review` → deliver.
75
+ Stages 2–5 do not run: there is nothing to plan and no mockup to render, the live slide is the
76
+ starting point (the in-app equivalent is the manager's route B, `approvedPlan: null`; the design
77
+ worker's small-edit fast path keeps no todo board at all). Updating `plan.md` afterwards is optional
78
+ bookkeeping and never re-opens the plan gate — once a deck has passed a review, the CLI treats
79
+ `plan.md` as a record, not a contract. The full route definitions are in *Intake → plan* below; new
80
+ slides added to an existing deck are from-scratch work and run the full list.
81
+
82
+ **Deliver is the last todo — the task ends when the slides are delivered.** Don't add a "sanity
83
+ pass" or "report back" step after it: the visual QA already happened at the draft check and the user
84
+ already approved at the review gate, so on approval you push/build directly and stop. Each stage's
85
+ full definition and the ordering invariants live in the bundle's `workflow/flow.md` — read it right
86
+ after `ready` succeeds.
87
+
88
+ **Concept mockups (stage 4) are a mandatory authoring stage, not an optional aid.** After plan
89
+ sign-off, for anything authored from an approved plan — one slide as much as a deck — you **always**
90
+ run `slidemind concepts <deck>` and
91
+ **immediately Read every generated `concept-slide-NN.png` at full detail**. Use this first,
92
+ deck-wide viewing pass to inventory the imagery, pictograms, factual/content checks, and other
93
+ searches each slide needs; do those searches before authoring. This discovery read does **not**
94
+ replace the fresh per-batch concept read immediately before JSX creation in *The create flow*.
95
+ The durable visual anchors are the repo-relative files under
96
+ `decks/<slug>/concepts/concept-slide-NN.png`, never an earlier chat image or temporary attachment;
97
+ after any continuation, re-list that directory and reopen the files from those paths.
98
+ Rebuild each mockup toward its target — this is the local-harness equivalent of the in-app manager's
99
+ *unconditional* concept pass on every from-scratch delegation (`generateConceptImages` fires for
100
+ every delegation carrying an approved plan). It degrades benignly: if it returns no mockups (exit 0 —
101
+ the add-in can't generate them) you author from the storyboards alone, but the *attempt* is not
102
+ optional. Skip it only for targeted work on slides that **already exist** — an edit or a rework,
103
+ which designs from the live slide and never had a plan to render mockups from.
34
104
 
35
105
  Two gate invariants you must never break — one per gate, equally binding:
36
106
 
37
- - **Never jump from clarify to authoring for a deck** — the plan sign-off gate (`slidemind plan <deck>`, stage 3) always sits between. Writing `decks/<slug>/slides/*.jsx` before that gate has returned `DECISION: approved` is the single most common way this workflow goes wrong — it means the user never actually signed off on the story. The only exception is a single slide or a tiny set genuinely handled in-chat (*Intake → plan* below) — that's a real design choice, not a shortcut to take when a deck-sized request feels obvious.
38
- - **Never jump from authoring to deliver** — the draft check and an approved review gate always sit between.
107
+ - **Never jump from clarify to authoring** — the plan sign-off gate (`slidemind plan <deck>`,
108
+ stage 3) always sits between. Writing `decks/<slug>/slides/*.jsx` before that gate has
109
+ returned `DECISION: approved` is the single most common way this workflow goes wrong — it means
110
+ the user never actually signed off on the story. **There is no small-request exception**: one new
111
+ slide runs the same gate with a one-beat plan. The only work that skips it is a change to slides
112
+ that already exist.
113
+ - **Never jump from authoring to deliver** — the draft check and an approved review gate always sit
114
+ between.
115
+
116
+ ## After a context summarization (compaction recovery)
117
+
118
+ Long deck runs can exceed the context window mid-task; the harness then replaces the transcript
119
+ with a summary. **Everything you only held in chat — viewed concept images, search results, the
120
+ asset inventory, workflow rules you read from the bundle — is gone; the files on disk are not.**
121
+ When you notice you are running from a summary (or after any interruption/continuation), do NOT
122
+ improvise from the summary and do NOT restart finished work. Recover state from disk, in this
123
+ order, then resume at the first incomplete stage:
124
+
125
+ 1. `decks/<slug>/plan.md` — the approved story.
126
+ 2. `decks/<slug>/asset-plan.md` — per-slide organisms + which assets are downloaded vs. missing
127
+ (unchecked items still need their search + fetch).
128
+ 3. `ls decks/<slug>/slides/ decks/<slug>/assets/ decks/<slug>/concepts/` — what already exists.
129
+ 4. Re-read `<bundle>/workflow/create.md` if you are still before or inside authoring, and reopen
130
+ the concept PNGs for the slides not yet authored (batches of ≤3) before writing them.
131
+
132
+ The stage todo list still binds after a summary: a summary that says the deck is "mostly done" is
133
+ never a reason to skip the remaining stages (assets, draft check, review gate).
39
134
 
40
135
  ## Bootstrap (set yourself up — don't make the user do it)
41
136
 
42
- **The first step of every session is `slidemind ready`** (continuing an existing deck: `slidemind ready <deck>`). In one call it verifies authorization, 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.
43
-
44
- - **Exit 0** → you're fully set up. Read `workflow/flow.md` (the stage spine) and `design.md` from the reported `bundleDir` and start planning.
45
- - **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.)
46
-
47
- `ready` drives the `slidemind` CLI, which reaches PowerPoint through the add-in's **cloud relay** — no local server. Patch a missing CLI yourself; **connecting** needs the user once (they hold the add-in's identity):
48
-
49
- - **CLI missing** (`slidemind` not on `PATH`): `npm install -g slidemind` — that alone is the fix. Only run `slidemind init --for <claude|codex|opencode|all>` ((re)deploys this skill) when this skill did **not** come from a plugin: if the `SKILL.md` you are reading sits under a harness plugin cache (`~/.claude/plugins/…`, `~/.codex/plugins/…`), the plugin already supplies it and `init` would plant a second copy that drifts on the next plugin update. `npx slidemind <command>` runs one-off without a global install; `slidemind --version` confirms PATH; `slidemind update` upgrades (`--ref <version>` to pin) — unless the CLI itself came from a plugin, in which case update it there.
50
- - **Not connected:** `ready` exits with `not_connected` — the CLI cannot start a connection by itself, because the claim that carries the deployment's address is minted in the add-in. Ask the user to open PowerPoint → slidemind → **Settings → General → Connect CLI**, press the **link button**, and copy the command shown (press **CLI already installed?** for the short `slidemind setup …` form). Have them paste it to you and run it **verbatim** — it connects, refreshes the skills, and runs `ready` itself. Add `--no-install --for none` only if their install must not be touched. `slidemind whoami` lists connected environments.
51
-
52
- The CLI is **multi-environment**: connect 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 first-use authorization with `--backend <url>`; scope later calls with `--backend <url|env>`.) A normal user connects to the baked-in production backend only.
137
+ **The first step of every session is `slidemind ready`** (continuing an existing deck: `slidemind
138
+ ready <deck>`). In one call it verifies authorization, connection, and CLI version; resolves the
139
+ design the add-in has open; downloads or refreshes that design's bundle; and — given a deck arg —
140
+ binds the deck to it.
141
+
142
+ - **Exit 0** → you're fully set up. Read `workflow/flow.md` (the stage spine) and `design.md` from
143
+ the reported `bundleDir` and start planning.
144
+ - **Non-zero** → the CLI names exactly one blocker and one `nextAction`; do what it says. (The two
145
+ blockers that ever need the user are handled in *First step* below.)
146
+
147
+ `ready` drives the `slidemind` CLI, which reaches PowerPoint through the add-in's **cloud relay** —
148
+ no local server. Patch a missing CLI yourself; **connecting** needs the user once (they hold the
149
+ add-in's identity):
150
+
151
+ - **CLI missing** (`slidemind` not on `PATH`): `npm install -g slidemind` — that alone is the fix.
152
+ Only run `slidemind init --for <claude|codex|opencode|all>` ((re)deploys this skill) when this
153
+ skill did **not** come from a plugin: if the `SKILL.md` you are reading sits under a harness
154
+ plugin cache (`~/.claude/plugins/…`, `~/.codex/plugins/…`), the plugin already supplies it and
155
+ `init` would plant a second copy that drifts on the next plugin update. `npx slidemind <command>`
156
+ runs one-off without a global install; `slidemind --version` confirms PATH; `slidemind update`
157
+ upgrades (`--ref <version>` to pin) — unless the CLI itself came from a plugin, in which case
158
+ update it there.
159
+ - **Not connected:** `ready` exits with `not_connected` — the CLI cannot start a connection by
160
+ itself, because the claim that carries the deployment's address is minted in the add-in. Ask the
161
+ user to open PowerPoint → slidemind → **Settings → General → Connect CLI**, press the **link
162
+ button**, and copy the command shown (press **CLI already installed?** for the short `slidemind
163
+ setup …` form). Have them paste it to you and run it **verbatim** — it connects, refreshes the
164
+ skills, and runs `ready` itself. Add `--no-install --for none` only if their install must not be
165
+ touched. `slidemind whoami` lists connected environments.
166
+
167
+ The CLI is **multi-environment**: connect once per backend (local / dev / prod) and every command
168
+ fans out across all of them, tags each open window with its `env`, and routes to the right backend
169
+ automatically — no manual switching. (Scope first-use authorization with `--backend <url>`; scope
170
+ later calls with `--backend <url|env>`.) A normal user connects to the baked-in production backend
171
+ only.
53
172
 
54
173
  ## Connecting the CLI (one-time; you guide the user)
55
174
 
@@ -58,68 +177,271 @@ PowerPoint — not here. Every organization runs its own slidemind backend, so a
58
177
  unconnected CLI has no address to reach and nothing to discover it from; the
59
178
  authenticated add-in knows both, and mints a one-time claim carrying its address.
60
179
 
61
- **1 — Ask for the command.** Tell the user to open the **slidemind add-in** task pane → **Settings** → **General** → **Connect CLI**, press the **link button**, and press **Copy command**. If they already have the CLI, **CLI already installed?** swaps it to the shorter `slidemind setup …` form; either works.
180
+ **1 — Ask for the command.** Tell the user to open the **slidemind add-in** task pane → **Settings**
181
+ → **General** → **Connect CLI**, press the **link button**, and press **Copy command**. If they
182
+ already have the CLI, **CLI already installed?** swaps it to the shorter `slidemind setup …` form;
183
+ either works.
62
184
 
63
- **2 — Run it verbatim.** Paste it exactly as given. It redeems the claim, saves the session, installs the CLI globally if needed, deploys the skills into every coding agent on the machine, and finishes by running `ready` — so no `init` and no add-in restart belong to this flow.
185
+ **2 — Run it verbatim.** Paste it exactly as given. It redeems the claim, saves the session,
186
+ installs the CLI globally if needed, deploys the skills into every coding agent on the machine, and
187
+ finishes by running `ready` — so no `init` and no add-in restart belong to this flow.
64
188
 
65
- **3 — If it fails.** A claim works once and expires in ~10 minutes; on *already used or expired*, ask for a fresh one. The pane flips to **Connected** by itself once the claim is spent.
189
+ **3 — If it fails.** A claim works once and expires in ~10 minutes; on *already used or expired*,
190
+ ask for a fresh one. The pane flips to **Connected** by itself once the claim is spent.
66
191
 
67
192
  ## First step — `slidemind ready` (before anything else, every time)
68
193
 
69
- 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 (a saved session → 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`.
70
-
71
- - **New work:** `slidemind ready` — resolves + materializes the open design's bundle so you can read its `design.md` while planning.
72
- - **Continuing a deck:** `slidemind ready <deck>` — same, and (re)binds the deck to whatever design is open.
73
-
74
- **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.
75
-
76
- **On exit 0** the JSON reports `presId`, `presFP`, `designName`, `bundleDir`, `bundleEtag`, `bound`, `paneSuspended`, and `engines` (`{available, envs}` — whether engine search reaches the corpus without a window), 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/`, 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` — the pane ops wait for a pane click on their own; **don't treat it as a blocker.**
77
-
78
- **A bound deck readies with NO window at all — that is the normal case, not a degraded one.** `slidemind ready <deck>` for a deck that was bound once before exits 0 with `windowless: true` even when PowerPoint is closed: the design identity lives in the deck's `.bundle-ref.json` and the bundle syncs over a pane-free route, so its ladder is *session → bundle freshness → engine reachability*, with **no pane precondition** — the pane is reported, never required. In that state authoring, `view-draft`, `build`, `review`, `build-pptx`, and (where `engines.available` is true) engine search and download all work end-to-end; only `push`'s insert, `insert-slide`, and `read <presId>` of an open presentation need a window — the `nextAction` says exactly that. Don't ask the user to open PowerPoint until one of those is actually next.
79
-
80
- **Microsoft 365 sign-in — automatic on first need; just let it happen.** The engine surface — corpus search, brand-imagery downloads, slide extraction — runs **as the user**. `ready` reports the state (JSON: `m365.signedIn`, `m365.degradation`) so you know it's coming, but you never initiate it: the first engine command opens the user's browser ITSELF, prints `Microsoft 365 sign-in needed — opening your browser…`, and **blocks until the human finishes**. When that line appears, tell the user to complete the sign-in in the browser (you cannot) and keep waiting — don't kill or re-run the command. One sign-in lasts ~90 days. Rendering, bundles, and already-materialized assets never need it, so a pure author→render session runs signed-out without ever seeing this.
81
-
82
- For a deck that was **never** bound and no window is open, `ready` asks the backend which corporate designs the user may build against: exactly one binds automatically, several stop with `ambiguous_brand` (below).
83
-
84
- **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.** These are the ones that need the user:
85
-
86
- - **`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.
87
- - **`ambiguous_brand`** — the same question with no window to ask it from: the backend offers several designs (`brands[]`, each with a `name` and `env`). Ask the user by **name**, then re-run `slidemind ready [deck] --brand <presFP>`.
88
- - **`login_required`** — the automatic browser sign-in was refused or abandoned, so **corpus search and engine downloads** stop until the user runs `slidemind login` (browser step, whenever they're ready). It never blocks authoring, rendering, or the bundle — relay the line, keep working, and re-run the search after they've signed in. When a slidemind pane is already open the CLI says so and routes the search through that window instead: follow what it printed.
89
- - **Connection blockers** (`not_connected`, `all_unreachable`, `cli_update_required`, `no_window`, `not_render_ready`) — relay the CLI's `nextAction` verbatim (copy the setup command / open PowerPoint / click the pane / run `slidemind update`). Connecting is walked through above. (`no_window` only ever surfaces for a deck that is neither bound nor bindable from the backend's design list — a bound deck rides the pane-free rung above instead.)
90
-
91
- **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) → `slidemind concepts <slug>` (mandatory concept-mockup pass for a deck, then rebuild toward each) → 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>`.
92
-
93
- **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 whole authoring loop is host-free for a bound deck** — intake → plan → concepts → author → `view-draft` → `review` → `slidemind build-pptx <deck> [--out <file>]` — because the render captures the slides with a local headless browser and assembles the `.pptx` server-side over the pane-free brand route (streaming its own `rendering slide n/m…` progress), and engine discovery, search, downloads, and slide reuse run off the connection wherever the add-in serves them (`engines.available` in `ready`'s payload; older add-ins relay them through a pane instead). Exactly three things need a live PowerPoint: **`push`'s insert**, **`insert-slide`**, and **`read <presId>`** of an open presentation. Where a pane *is* involved, the CLI handles the wait itself: up to ~2 min, one *"click the slidemind pane"* line when user help is genuinely needed, then a safe retry. 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.
94
-
95
- `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 — so *"a `.pptx` file to send around"* is deliverable end-to-end with PowerPoint closed.
194
+ Everything about how a deck is authored, styled, and rendered is shaped by the corporate design
195
+ **the add-in has open**, and every brand rule you follow is read from that design's **materialized
196
+ bundle**. `slidemind ready` gets you there in one call: it walks the connection ladder (a saved
197
+ session → reachable backend → CLI version), picks which design to build against, downloads or
198
+ refreshes that design's bundle (incremental — unchanged files cost nothing), and — when you pass a
199
+ deck — binds the deck to it by writing `<deck>/.bundle-ref.json`. PowerPoint does not have to be
200
+ open: the designs cached on this machine are a first-class source.
201
+
202
+ - **New work:** `slidemind ready` — picks + materializes a design's bundle so you can read its
203
+ `design.md` while planning.
204
+ - **Continuing a deck:** `slidemind ready <deck>` — same, and the deck's own binding is what it
205
+ picks.
206
+
207
+ **The design is the user's choice; `ready` only picks a sensible default.** Its order is: an
208
+ explicit `--brand <presFP>`, else the deck's own `.bundle-ref.json`, else the one design the
209
+ verified live PowerPoint windows agree on (a window whose pane is only suspended never outranks a
210
+ live one), else the one design cached here, else the one design the backend lists. Anything
211
+ that leaves several candidates is the `ambiguous_design` blocker (below). A live window is a
212
+ suggestion, never an authority: it only decides when nothing stronger says otherwise. And whatever
213
+ `ready` picked, when its `designs` list holds more than one entry the design is a Clarify question
214
+ (below), and the answer is applied with `slidemind ready [deck] --brand <presFP>` before anything
215
+ is planned.
216
+
217
+ **On exit 0** the JSON reports `presId`, `presFP`, `designName`, `designs` (every design at hand
218
+ — cached on this machine, open in a verified window, or listed by the backend — `{presFP, name,
219
+ colors, current, cached, windows}`, `colors` being the master's theme colours as hex,
220
+ `dk1`/`lt1`/`dk2`/`lt2`/`accent1..6`, `windows` the open PowerPoint windows on that design),
221
+ `windows` (every verified open window — `{presId, env, title, fileName, presFP, paneReady}`; a
222
+ window PowerPoint no longer has is pruned before anything is decided), `bundleDir`, `bundleEtag`,
223
+ `bound`, `paneSuspended`, and `engines` (`{available, envs}` — whether engine search reaches the
224
+ corpus without a window), with `nextAction: "Ready."`. Read `workflow/flow.md` and `design.md` from
225
+ `bundleDir` (cached at `${XDG_CACHE_HOME:-~/.cache}/slidemind/bundles/<presFP>/`, alongside
226
+ `corporate-design.css`, `layouts/*.jsx`, `layouts/layouts.css`, `assets/`, and the rest
227
+ of the add-in-owned `workflow/*.md`) and start planning. A render-ready window whose pane is
228
+ suspended still exits 0 with `paneSuspended: true` — the pane ops wait for a pane click on their
229
+ own; **don't treat it as a blocker.**
230
+
231
+ **A bound deck readies with NO window at all — that is the normal case, not a degraded one.**
232
+ `slidemind ready <deck>` for a deck that was bound once before exits 0 with `windowless: true` even
233
+ when PowerPoint is closed: the design identity lives in the deck's `.bundle-ref.json` and the bundle
234
+ syncs over a pane-free route, so its ladder is *session → bundle freshness → engine reachability*,
235
+ with **no pane precondition** — the pane is reported, never required. In that state authoring,
236
+ `view-draft`, `build`, `review`, `build-pptx`, and (where `engines.available` is true) engine search
237
+ and download all work end-to-end; only `push`'s insert, `insert-slide`, and `read <presId>` of an
238
+ open presentation need a window — the `nextAction` says exactly that. Don't ask the user to open
239
+ PowerPoint until one of those is actually next.
240
+
241
+ **Microsoft 365 sign-in — automatic on first need; just let it happen.** The engine surface — corpus
242
+ search, brand-imagery downloads, slide extraction — runs **as the user**. `ready` reports the state
243
+ (JSON: `m365.signedIn`, `m365.degradation`) so you know it's coming, but you never initiate it: the
244
+ first engine command opens the user's browser ITSELF, prints `Microsoft 365 sign-in needed — opening
245
+ your browser…`, and **blocks until the human finishes**. When that line appears, tell the user to
246
+ complete the sign-in in the browser (you cannot) and keep waiting — don't kill or re-run the
247
+ command. One sign-in lasts ~90 days. Rendering, bundles, and already-materialized assets never need
248
+ it, so a pure author→render session runs signed-out without ever seeing this.
249
+
250
+ For a deck that was **never** bound and no window is open, the one design cached here binds
251
+ automatically; with nothing cached `ready` asks the backend which corporate designs the user may
252
+ build against, and exactly one binds. Several of either stop with `ambiguous_design` (below).
253
+
254
+ **On non-zero** the CLI names exactly one blocker `{code, actor, message}` and one `nextAction`.
255
+ **The CLI owns the remediation text — relay `nextAction`, don't restate it.** These are the ones
256
+ that need the user:
257
+
258
+ - **`ambiguous_design`** — several corporate designs are at hand and nothing says which: several
259
+ live windows on different designs, or no live window and several designs cached / listed by the
260
+ backend. The payload is the same `designs` menu as on success (name, `colors`, `cached`, and
261
+ the open `windows` on each) plus `windows`; if the deck was last built against one of them its
262
+ `presFP` is `suggested`. **Ask the user which design to build against exactly as the Clarify
263
+ question below does — by name and colours, naming any open window on it by `title`/`fileName`,
264
+ never by raw id** — and mention the suggested one if present ("this deck was last built against
265
+ X — continue with it?"). Then re-run `slidemind ready [deck] --brand <presFP>` for the design
266
+ they pick (`--to <presId>` also works when they named a window).
267
+ - **`login_required`** — the automatic browser sign-in was refused or abandoned, so **corpus search
268
+ and engine downloads** stop until the user runs `slidemind login` (browser step, whenever they're
269
+ ready). It never blocks authoring, rendering, or the bundle — relay the line, keep working, and
270
+ re-run the search after they've signed in. When a slidemind pane is already open the CLI says so
271
+ and routes the search through that window instead: follow what it printed.
272
+ - **Connection blockers** (`not_connected`, `all_unreachable`, `cli_update_required`, `no_window`,
273
+ `not_render_ready`) — relay the CLI's `nextAction` verbatim (copy the setup command / open
274
+ PowerPoint / click the pane / run `slidemind update`). Connecting is walked through above.
275
+ (`no_window` only ever surfaces for a deck that is neither bound nor bindable from the backend's
276
+ design list — a bound deck rides the pane-free rung above instead.)
277
+
278
+ **The session spine** (= the stage todos you created up front): `slidemind ready` → read
279
+ `workflow/flow.md` + `design.md` from `bundleDir` → intake/plan (below) → `slidemind new <slug>`
280
+ (scaffolds **and** auto-binds the deck to the open design — zero extra download, because `ready`
281
+ already materialized it; `--brand <presFP>` binds to the design the user chose instead) → `slidemind plan <slug>` (plan sign-off gate for every
282
+ from-scratch request, one slide included) → `slidemind concepts <slug>` (mandatory concept-mockup pass for everything
283
+ authored from a plan, then rebuild toward each) → author → `view-draft` → `review` (mandatory, the moment the deck builds clean) →
284
+ deliver (`push` / `build-pptx`). `slidemind new` best-effort binds when the open design is
285
+ unambiguous and the bundle is already materialized; if it can't (ambiguous, or no host), it
286
+ scaffolds anyway and hints to run `slidemind ready <slug>`.
287
+
288
+ **Backgrounded — or closed — PowerPoint is expected to work.** Do not pre-emptively ask the user to
289
+ focus PowerPoint or the task pane, and never ask them to keep it foregrounded while something runs.
290
+ **The whole authoring loop is host-free for a bound deck** — intake → plan → concepts → author →
291
+ `view-draft` → `review` → `slidemind build-pptx <deck> [--out <file>]` — because the render captures
292
+ the slides with a local headless browser and assembles the `.pptx` server-side over the pane-free
293
+ brand route (streaming its own `rendering slide n/m…` progress), and engine discovery, search,
294
+ downloads, and slide reuse run off the connection wherever the add-in serves them
295
+ (`engines.available` in `ready`'s payload; older add-ins relay them through a pane instead). Exactly
296
+ three things need a live PowerPoint: **`push`'s insert**, **`insert-slide`**, and **`read
297
+ <presId>`** of an open presentation. Where a pane *is* involved, the CLI handles the wait itself: up
298
+ to ~2 min, one *"click the slidemind pane"* line when user help is genuinely needed, then a safe
299
+ retry. If you see that line, relay it once and keep waiting — do not rebuild, re-plan, or babysit.
300
+ If a `push` can't deliver (pane never woke, or no window at all), the rendered `.pptx` was saved
301
+ next to the deck (`paneSuspended` + `fallbackFile` in the result) — nothing is lost; re-run the push
302
+ once a window exists. Reserve the full "open PowerPoint…" instruction for when a command actually
303
+ reports it as the blocker.
304
+
305
+ `slidemind build`, `review`, and `view-draft` run offline, but only against a **previously
306
+ materialized** bundle — so `ready` (or a prior `ready`) must have succeeded at least once.
307
+ `build-pptx` additionally needs the backend reachable (the OOXML assembly is server-side), but no
308
+ PowerPoint window for a bound deck — so *"a `.pptx` file to send around"* is deliverable end-to-end
309
+ with PowerPoint closed.
96
310
 
97
311
  ## Two UX rules (gates + host)
98
312
 
99
- - **Announce every gate, with a clickable link.** The moment `slidemind plan` or `slidemind review` starts it prints `ready at <url>` and a `BROWSER:` status line. Immediately tell the user in chat whether a browser tab opened (new tab / reused tab / failed to open) and give the gate URL as a clickable link — every round, and again whenever you report that you're still waiting on their decision.
100
- - **Add-in unreachable → block and name the tab.** When a genuinely host-required command (`push`'s insert, `insert-slide`, `read <presId>`) can't reach the add-in (a connection blocker, a pane that never wakes, the *click the slidemind pane* line with no effect), **stop the workflow** — don't skip the step, work around it, or retry silently. Ask the user to go back into the PowerPoint tab of presentation **<title/fileName>** (name it from the command output or `slidemind presentations` — never a raw id), then re-run the failed command once they have. Everything before delivery keeps running meanwhile — never park the whole task on a window it doesn't need.
313
+ - **Announce every gate, with a clickable link.** The moment `slidemind plan` or `slidemind review`
314
+ starts it prints `ready at <url>` and a `BROWSER:` status line. Immediately tell the user in chat
315
+ whether a browser tab opened (new tab / reused tab / failed to open) and give the gate URL as a
316
+ clickable link — every round, and again whenever you report that you're still waiting on their
317
+ decision.
318
+ - **Add-in unreachable → block and name the tab.** When a genuinely host-required command (`push`'s
319
+ insert, `insert-slide`, `read <presId>`) can't reach the add-in (a connection blocker, a pane that
320
+ never wakes, the *click the slidemind pane* line with no effect), **stop the workflow** — don't
321
+ skip the step, work around it, or retry silently. Ask the user to go back into the PowerPoint tab
322
+ of presentation **<title/fileName>** (name it from the command output or `slidemind presentations`
323
+ — never a raw id), then re-run the failed command once they have. Everything before delivery keeps
324
+ running meanwhile — never park the whole task on a window it doesn't need.
101
325
 
102
326
  ## Intake → plan (you own this; do it in chat)
103
327
 
104
- 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.
105
-
106
- - **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.
107
- - **Interview just enough** to pin: audience/goal, the content and its sources (none / pasted / local files / existing deck / web research — a source that's already a local `.pptx` you read host-free with `slidemind read <file.pptx>`), 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). If the content source resolves to "none", don't silently plan from generic knowledge — say so, and either interview the user for the substance (their claims, numbers, examples) or offer web research before writing storyboards.
108
- - **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).
109
- - **Replay and get sign-off.** Single slides / tiny sets → a compact in-chat plan (no gate). Decks → persist a **story-focused plan with body storyboards** in `decks/<slug>/plan.md`, two top-level sections in order:
110
- - `## Red thread` — one presentation **move** per slide, as bullets or one arrow-separated line. The number of moves MUST equal the number of `### Slide N` sections: when the user names a slide count, write exactly that many moves and sections — never expand the narrative arc beyond the requested count. Name the *teaching function* of each slide — short verb+noun labels for what the audience is doing cognitively at that step — never its content: no claims, facts, metrics, client-specific terms, slide copy, generic section names, or wording copied from these instructions.
111
- - `## Per-slide storyboards` — one `### Slide N: <role>` subsection per slide, each a one-sentence `Core message:` followed by **exactly one** fenced `storyboard-canvas` JSON block.
112
-
113
- The `storyboard-canvas` is a **body-only spatial sketch**, not final slide design: it plans the body region only and never the template title/header/footer/logo/slide-number areas. Blocks live in a 1600 × 900 coordinate space, kept inside the body-safe area (roughly x 80–1520, y 110–780); position, size, and proximity must express the slide's meaning — hierarchy, sequence, causality, contrast, grouping, flow direction, or the main focus — not random placement. Each block shows only two visible text fields: `designElement` (the visual mechanism in up to 5 words — e.g. "hub-spoke visual", "loop diagram", "timeline", "matrix", "before/after contrast", "scorecard") and `content` (a 1–2 word label), plus `emphasis` ("primary"/"secondary"/"tertiary") for hierarchy. `keyMessage` is the slide's **story beat**: one plain sentence naming what this slide does to move the story forward, stated abstractly — NOT the headline or copy that will appear on the slide, and not the red-thread move restated. `contentNotes` is the **content draft** that delivers that beat — facts, claims, examples, source points, caveats, draft copy, proof points — and carries no design, layout, tone, or authoring-process instructions. It is the slide's full content budget: the create stage and the concept-mockup generator build from `contentNotes` alone and never add substance, so anything not in the notes will not be on the slide. Write them so the slide body could be authored from them without inventing anything — every claim spelled out concretely, with the numbers, named examples, or proof points that make it land. Two or three abstract topic bullets ("X is expensive", "Y improves") is an unfinished draft, not a storyboard.
114
-
115
- Judge whether two or more slides form a genuine visual series — for example a continuation, progressive reveal, repeated comparison, phased journey, or recurring framework. When they do, give those storyboard objects the same short, stable `visualFamily` identifier. Do not group slides merely because they share a topic, and do not ask the user to make this design judgment. A family tells concept generation to establish one recognizable visual system and adapt it to every member's own `keyMessage`, `contentNotes`, role, and structure. It never permits copying another slide's text, claims, data, or exact geometry, and it never permits dropping approved content to fit the shared concept. Omit `visualFamily` for independent slides.
116
-
117
- Choose the block count from the slide's meaning and **never default to three** (1 for a hero idea, 2 for a contrast or paired tension, 3 only for three genuinely distinct beats, 4–5 only for a true sequence or comparison set), and vary the spatial composition across slides — avoid repeating the same left/right/bottom alignment. Ban style micromanagement only — no colours, fonts, exact layout names, or final box/card counts: **the create stage owns realisation** of the approved body storyboard in the corporate design. Use this exact JSON shape:
328
+ This is your mapping of `workflow/flow.md` stages 1–2 (*clarify* + *plan sign-off*). In-app, a
329
+ manager runs these; over the CLI the manager role collapses onto **you**, so you run the interview
330
+ and the sign-off directly with the user. Don't write slide JSX until the plan is agreed.
331
+
332
+ **First read which of three things the user wants**, from their words plus what you already have —
333
+ the deck you are working in, the file they pointed at, what you built for them a moment ago. Judge it
334
+ yourself and ask only when the request genuinely reads both ways. **Slide count never decides the
335
+ route; intent does.**
336
+
337
+ - **Author something new** ("a slide about X", "a deck for Friday", "add a closing slide", filling an
338
+ empty placeholder) → the full spine: plan → `slidemind plan` → `slidemind concepts` → author →
339
+ `view-draft` → `review` → deliver. One slide runs every one of those stages, just smaller.
340
+ - **Change slides that already exist** ("make slide 4 stronger", "fix the spacing", "retitle these
341
+ three") → **no plan, no concepts**: there is nothing to plan, the live slide is the starting point.
342
+ Read `workflow/edit.md`, patch that slide's own `.jsx` (adopt a foreign slide on first touch), then
343
+ `view-draft` → `review` → deliver. The review gate still runs — over the CLI the deliver happens
344
+ out of the user's sight, so it is the only place they see the change.
345
+ - **Reuse something that already exists elsewhere** ("do we have a slide on X?", "drop in our pricing
346
+ slide", "put our lighthouse icon here") → that is **`slidemind-search`**, not this create flow:
347
+ `slidemind search` → `download-result` / `add-slide`. Reuse is not authoring — no plan, no
348
+ concepts.
349
+
350
+ A request can carry two of them ("find our pricing slide and write a summary after it") — run each
351
+ part on its own route instead of forcing the whole thing onto one.
352
+
353
+ - **Read scope from the wording**, don't ask redundantly: single slide ("make a slide about X"),
354
+ small set ("add three slides on Y"), or whole deck ("a deck for Friday"). Only ask "one slide, a
355
+ small set, or a full deck?" when truly ambiguous.
356
+ - **Which corporate design — ask whenever more than one is cached.** `ready`'s `designs` list is
357
+ the menu: with a single entry there is no question; with several, put the choice to the user
358
+ **before planning**, even if PowerPoint has one of them open (that one is only the suggestion).
359
+ Never pick silently and never default to the open window or the deck's last binding — those
360
+ only chose `ready`'s `current` default, not the user's answer. Name each
361
+ design **and show its colours** so the user recognises it — the `name` plus its theme hexes in a
362
+ fixed order (`<name> — accent <accent1>, dark <dk1>, light <lt1>`, each a hex from `colors`; a
363
+ design without `colors` is listed by name alone), mark the `current` one, and ask which to build
364
+ against. Then
365
+ apply the answer: `slidemind ready [deck] --brand <presFP>` for the session, and `slidemind new
366
+ <slug> --brand <presFP>` when scaffolding a new deck. A design the user names that is not in the
367
+ list is not cached yet — `slidemind ready --brand <presFP>` fetches it when the backend serves
368
+ it; otherwise it must be opened in PowerPoint once.
369
+ - **Interview just enough** to pin: audience/goal, the content and its sources (none / pasted /
370
+ local files / existing deck / web research — a source that's already a local `.pptx` you read
371
+ host-free with `slidemind read <file.pptx>`), and the slide outline (each slide's role + a layout
372
+ *job* like cover/agenda/section/quote/closing/body — the concrete brand layout is chosen later
373
+ against the bundle). If the content source resolves to "none", don't silently plan from generic
374
+ knowledge — say so, and either interview the user for the substance (their claims, numbers,
375
+ examples) or offer web research before writing storyboards.
376
+ - **Lock the output target — it decides your deliver command.** Into the open PowerPoint (`slidemind
377
+ push`), or a `.pptx` file (`slidemind build-pptx`) — or an HTML preview / a mix. Infer it when the
378
+ wording is clear ("add a slide to this deck" → push; "make me a deck I can send around" → a file)
379
+ and ask only when genuinely ambiguous — but **always confirm the concrete target before
380
+ delivering** (which window, or which output path).
381
+ - **Replay and get sign-off — always, at every size.** Persist a **story-focused plan with body
382
+ storyboards** in `decks/<slug>/plan.md` and run the gate on it, whether the request is one slide or
383
+ forty. A single slide gets the same document with one `### Slide N` section: shorter, never
384
+ skipped. Two top-level sections in order:
385
+ - `## Red thread` — one presentation **move** per slide, as bullets or one arrow-separated line.
386
+ The number of moves MUST equal the number of `### Slide N` sections: when the user names a slide
387
+ count, write exactly that many moves and sections — never expand the narrative arc beyond the
388
+ requested count. Name the *teaching function* of each slide — short verb+noun labels for what
389
+ the audience is doing cognitively at that step — never its content: no claims, facts, metrics,
390
+ client-specific terms, slide copy, generic section names, or wording copied from these
391
+ instructions.
392
+ - `## Per-slide storyboards` — one `### Slide N: <role>` subsection per slide, each a one-sentence
393
+ `Core message:` followed by **exactly one** fenced `storyboard-canvas` JSON block.
394
+
395
+ The `storyboard-canvas` is a **body-only spatial sketch**, not final slide design: it plans the
396
+ body region only and never the template title/header/footer/logo/slide-number areas. Blocks live
397
+ in a 1600 × 900 coordinate space, kept inside the body-safe area (roughly x 80–1520, y 110–780);
398
+ position, size, and proximity must express the slide's meaning — hierarchy, sequence, causality,
399
+ contrast, grouping, flow direction, or the main focus — not random placement. Each block shows
400
+ only two visible text fields: `designElement` (the visual mechanism in up to 5 words — e.g.
401
+ "hub-spoke visual", "loop diagram", "timeline", "matrix", "before/after contrast", "scorecard")
402
+ and `content` (a 1–2 word label), plus `emphasis` ("primary"/"secondary"/"tertiary") for
403
+ hierarchy. A `designElement` may also name the chart family when the beat is quantitative
404
+ ("waterfall revenue to EBIT", "combo: revenue bars + margin line", "column chart by quarter");
405
+ that is a plan-level choice the authoring stage honours unless the data cannot be shown that
406
+ way, in which case it says so at the review gate.
407
+ `keyMessage` is the slide's **story beat**: one plain sentence naming what this slide
408
+ does to move the story forward, stated abstractly — NOT the headline or copy that will appear on
409
+ the slide, and not the red-thread move restated. `contentNotes` is the **content draft** that
410
+ delivers that beat — facts, claims, examples, source points, caveats, draft copy, proof points —
411
+ and carries no design, layout, tone, or authoring-process instructions. It is the slide's full
412
+ content budget: the create stage and the concept-mockup generator build from `contentNotes` alone
413
+ and never add substance, so anything not in the notes will not be on the slide. Write them so the
414
+ slide body could be authored from them without inventing anything — every claim spelled out
415
+ concretely, with the numbers, named examples, or proof points that make it land. Two or three
416
+ abstract topic bullets ("X is expensive", "Y improves") is an unfinished draft, not a storyboard.
417
+
418
+ Judge whether two or more slides form a genuine visual series — for example a continuation,
419
+ progressive reveal, repeated comparison, phased journey, or recurring framework. When they do,
420
+ give those storyboard objects the same short, stable `visualFamily` identifier. Do not group
421
+ slides merely because they share a topic, and do not ask the user to make this design judgment. A
422
+ family tells concept generation to establish one recognizable visual system and adapt it to every
423
+ member's own `keyMessage`, `contentNotes`, role, and structure. It never permits copying another
424
+ slide's text, claims, data, or exact geometry, and it never permits dropping approved content to
425
+ fit the shared concept. Omit `visualFamily` for independent slides.
426
+
427
+ Choose the block count from the slide's meaning and **never default to three** (1 for a hero idea,
428
+ 2 for a contrast or paired tension, 3 only for three genuinely distinct beats, 4–5 only for a true
429
+ sequence or comparison set), and vary the spatial composition across slides — avoid repeating the
430
+ same left/right/bottom alignment. Ban style micromanagement — no colours, fonts, or final
431
+ box/card counts: **the create stage owns realisation** of the approved body storyboard in the
432
+ corporate design. The ONE exception is the top-level `layout` field: **choose each slide's
433
+ layout at plan time** from `design.md` → Layout Catalog (a workhorse with a freeform body for
434
+ content slides; a purpose-built layout for covers/quotes/agendas; match the background tone —
435
+ light vs dark — to the slide's intended look) and set `"layout": "<ComponentName>"` on the
436
+ storyboard block. The concept generator uses it to render the mockup INTO that layout's actual
437
+ chrome and canvas, so the image you later rebuild already fits the stage it will live on. Use
438
+ this exact JSON shape:
118
439
 
119
440
  ```storyboard-canvas
120
441
  {
121
442
  "version": 1,
122
443
  "slide": 1,
444
+ "layout": "<ComponentName from design.md's Layout Catalog>",
123
445
  "blocks": [
124
446
  {
125
447
  "id": "main-visual",
@@ -141,93 +463,359 @@ This is your mapping of `workflow/flow.md` stages 1–2 (*clarify* + *plan sign-
141
463
  }
142
464
  ```
143
465
 
144
- Make the connection to the current deck explicit in the red thread, core messages, `keyMessage`, or `contentNotes` whenever the work extends the open presentation, and fold in any content findings from slides/files you inspected. Then run `slidemind plan <deck>`: it opens the plan as **editable storyboards** — the user reorders/renames/inserts/removes slides on the red-thread strip, drags/resizes/edits blocks and the content draft directly on each slide's canvas, and/or leaves comments anchored to a slide or to the whole story — and it **blocks until the user decides** — announce it per *Two UX rules* (browser opened? + the clickable gate URL) and 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 comments to `plan.md` — each is **slide-anchored** (`- [Slide 3: "<beat>"] …`) or whole-story, and the batch may include a **generated story-iteration instruction** (when the user restructured the red thread by adding or renaming slides, the gate asks you to build storyboards and content for exactly those moves while keeping the other slides intact) — (the round is persisted verbatim in `<deck>/plan-review.json` if your capture of the output was truncated). Change only what the comments require and keep unaffected slides verbatim (that is what makes the reviewer's per-slide "updated" badges meaningful), then **re-run the gate in the same turn**. **Expect several consecutive `DECISION: comments` rounds — that is the normal shape of a review, not an error.** The reviewer's tab stays live while you revise, so they keep reading and keep queueing comments; those queued comments are delivered by your next run, which then returns *immediately* with them (a drain round) instead of waiting. So never end your turn on a comments round, never claim to be "polling", and never send the user back to the browser between rounds — nothing reaches them until the gate runs again. Only `DECISION: approved` or `DECISION: pending` ends the loop; `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 storyboards **are** the approved plan; author from them.
145
-
146
- 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.**
466
+ Make the connection to the current deck explicit in the red thread, core messages, `keyMessage`,
467
+ or `contentNotes` whenever the work extends the open presentation, and fold in any content
468
+ findings from slides/files you inspected. Then run `slidemind plan <deck>`: it opens the plan as
469
+ **editable storyboards** — the user reorders/renames/inserts/removes slides on the red-thread
470
+ strip, drags/resizes/edits blocks and the content draft directly on each slide's canvas, and/or
471
+ leaves comments anchored to a slide or to the whole story — and it **blocks until the user
472
+ decides** — announce it per *Two UX rules* (browser opened? + the clickable gate URL) and give the
473
+ shell call a **generous timeout** (the gate waits up to 30 min; if your harness kills the call
474
+ early, just re-run it — the user's open tab reconnects). Outcomes: `DECISION: approved` → proceed
475
+ to author; `DECISION: comments` → apply the comments to `plan.md` — each is **slide-anchored** (`-
476
+ [Slide 3: "<beat>"] …`) or whole-story, and the batch may include a **generated story-iteration
477
+ instruction** (when the user restructured the red thread by adding or renaming slides, the gate
478
+ asks you to build storyboards and content for exactly those moves while keeping the other slides
479
+ intact) — (the round is persisted verbatim in `<deck>/plan-review.json` if your capture of the
480
+ output was truncated). Change only what the comments require and keep unaffected slides verbatim
481
+ (that is what makes the reviewer's per-slide "updated" badges meaningful), then **re-run the gate
482
+ in the same turn**. **Expect several consecutive `DECISION: comments` rounds — that is the normal
483
+ shape of a review, not an error.** The reviewer's tab waits while you revise (reading stays live,
484
+ commenting is off) and refreshes with your next run, which blocks until they decide again. So
485
+ never end your turn on a comments round, never claim to be "polling", and never send the user
486
+ back to the browser between rounds — nothing reaches them until the gate runs again. Only `DECISION: approved` or `DECISION:
487
+ pending` ends the loop; `DECISION: pending` → the gate timed out with no answer — not approval,
488
+ not rejection: don't author; wrap up telling the user the plan still awaits their sign-off and
489
+ re-run `slidemind plan <deck>` on their go-ahead. Loop until approved. A `plan.md` **approved in a
490
+ prior gate round and unchanged since** counts as approved (skip straight to authoring); any new or
491
+ revised plan must pass the gate. When the gate reports the user edited `plan.md` directly, re-read
492
+ it — the edited storyboards **are** the approved plan; author from them.
493
+
494
+ Keep planning about intent and content. The bundle is already materialized by `slidemind ready`, so
495
+ `design.md` is there if you need to sanity-check feasibility — but **don't dive into
496
+ brand/layout/composition detail until create/edit.**
147
497
 
148
498
  ## The create flow
149
499
 
150
- `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:
151
-
152
- 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.
153
- 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. The approved `plan.md` is a **content contract, not a rendering spec** — you drew its storyboards yourself, but approval covered the story and content, not the sketch's geometry; how to interpret the `storyboard-canvas` blocks at author time (design hypothesis: reinterpret freely, never transcribe coordinates, block geometry, or block labels) is owned by `workflow/create.md` → Preconditions. **Generate concept mockups first — mandatory for a deck (stage 4).** Before authoring a deck from an approved plan, run `slidemind concepts <deck>` — the local-harness equivalent of the in-app manager's *unconditional* concept pass (`generateConceptImages` fires for every `approvedPlan && !targetSlideScope` delegation). Then **Read** each `decks/<slug>/concepts/concept-slide-NN.png` as the per-slide design target and rebuild it under your constraints — the rebuild rule is owned by `workflow/create.md` → Preconditions (reproduce the mockup's composition, hierarchy, graphic mechanism, AND granularity — its organism count, badges, satellites, and annotation layers are part of the target, and restraint is a colour budget, never an element budget; texts follow the story). It never hard-fails: if it produces no mockups (exit 0 — the add-in can't generate them) author from the storyboards alone. Skip it only where the add-in's `!targetSlideScope` gate would — a single slide, a tiny in-chat set, or a targeted rework of existing slides.
154
- When storyboard objects share a `visualFamily`, rebuild those mockups as one recognizable visual series. The lowest-numbered member is the anchor. Preserve its shape vocabulary, framing, hierarchy, annotation style, illustration treatment, and spatial rhythm across the family, but adapt every member's element count, sizing, arrangement, labels, emphasis, and connections to its own complete `keyMessage`, `contentNotes`, role, and structure. Never copy another member's text, claims, or data, never force its exact geometry, and never omit approved content because it does not fit the anchor composition.
155
- 3. **Imagery from the engine.** Discover the available image engines by listing them — `slidemind ls engines --subtype image` (the local-harness equivalent of the in-app design agent's `list_engines` tool; no PowerPoint window needed where the add-in serves the pane-free engine routes) — judge which engine fits from its label and description, then search it and place results. (`slidemind search` without `--engine` picks an image engine the same way.) The engine search/reuse mechanics live in **`slidemind-search`** — use it to find and fetch imagery; the create-only detail — sizing a fetched asset's box and recolouring an icon — is in *Placing engine imagery* 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. The slide can come from an engine search **or** from a local `.pptx` on disk (`add-slide --from <file.pptx> --pick <n> --deck <slug>`, host-free); both fold in identically — see `slidemind-search`.
156
- 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.
157
- 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). Announce it per *Two UX rules*: tell the user the browser opened and give the clickable gate URL. **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:
158
- - `DECISION: approved` → proceed to the deliver the user chose at intake: `slidemind push <deck>` (into PowerPoint) or `slidemind build-pptx <deck>` (to a file).
159
- - `DECISION: comments` → the user left spatially-anchored notes, each citing a `slides/<file>.jsx:line:col`, the source line, the click position, and a **round tag** (`[2, round 1] …`) — plus a readonly-layout note where the click landed on a layout slot. A pin carrying an *older* round was dropped on the previous render, so read the file before you edit it rather than trusting the cited line blindly. **Edit the cited files in place at the given line and re-run `slidemind review <deck>` in the same turn.** **Expect several consecutive `DECISION: comments` rounds — that is the normal shape of a review, not an error.** The user's tab stays live while you fix: they keep browsing the preview and keep dropping pins, and those queued pins are delivered by your next run, which then returns *immediately* with them (a drain round) instead of waiting. So never end your turn on a comments round, never claim to be "polling", and never send the user back to the browser between rounds — nothing reaches them until the gate runs again. Addressed pins come back as read-only ghost pins so the user can confirm each note was worked in. Only `DECISION: approved` or `DECISION: pending` ends the loop. Nothing is exported on a comments round. **Every round is persisted verbatim in `<deck>/review.json`** — if your shell capture of the gate's output was truncated or lost (backgrounded command, clipped scrollback), read that file for the complete comment list; never guess at missing comments or ask the user to re-type them.
160
- - `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).
161
-
162
- `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.
163
-
164
- **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.
500
+ `slidemind ready` already resolved the design source and materialized its bundle; the deck was bound
501
+ to it by `slidemind ready <deck>` (continuing) or by `slidemind new <slug>`'s auto-bind (new work).
502
+ From here:
503
+
504
+ 1. **Load create context, then inspect the concepts.** Read the create-stage references together —
505
+ `workflow/create.md` (the procedure), `workflow/composition.md` (the composition baseline),
506
+ `workflow/layouts.md` (palette + working area), and `workflow/authoring.md` (the substrate rules)
507
+ — plus the deck's `design.md` and the specific `layouts/*.jsx` the plan uses. (That is the read
508
+ set `workflow/create.md` → Context loading prescribes; follow it as written — `workflow/flow.md`
509
+ you already read after `ready`.) The approved `plan.md` is a **content contract, not a rendering
510
+ spec** — you drew its storyboards yourself, but approval covered the story and content, not the
511
+ sketch's geometry; how to interpret the `storyboard-canvas` blocks at author time (design
512
+ hypothesis: reinterpret freely, never transcribe coordinates, block geometry, or block labels)
513
+ is owned by `workflow/create.md` → Preconditions. **Generate concept mockups first — mandatory
514
+ for everything authored from a plan, a single slide included (stage 4).** Before
515
+ authoring from an approved plan, run `slidemind concepts <deck>` — the local-harness
516
+ equivalent of the in-app manager's *unconditional* concept pass (`generateConceptImages` fires
517
+ for every delegation carrying an approved plan). **Immediately after generation, Read
518
+ every `decks/<slug>/concepts/concept-slide-NN.png` at full detail, before any engine or content
519
+ search.** First list the directory and keep the literal repo-relative mapping in the task context:
520
+ concept `NN` maps to `decks/<slug>/concepts/concept-slide-NN.png` and later to the `NN-*.jsx`
521
+ slide. These workspace files are the durable source of truth across turns and compaction — never
522
+ rely on an earlier rendered attachment. Inventory what each mockup requires — imagery, distinct
523
+ pictograms, factual/content verification, annotations, and other visible organisms — and
524
+ **persist the inventory to disk the moment you finish it: write `decks/<slug>/asset-plan.md`**,
525
+ one section per slide:
526
+
527
+ ```
528
+ ## Slide NN — <title>
529
+ organisms: <the mockup's regions, hero figure, badges, satellites, chips, connectors>
530
+ - [ ] icon: <what it depicts> — query: "<search query>"
531
+ - [ ] image: <what it shows> — query: "<search query>"
532
+ ```
533
+
534
+ Chat context is evicted when the conversation is summarized; this file is not. Every icon
535
+ decision you make only in your head is lost at the next compaction — the file is the contract
536
+ step 2 executes and step 3 authors from. Check items off (`- [x] … — assets/engine-<id>-<n>.svg`)
537
+ as downloads land, so the file always shows what is still missing. This first pass is
538
+ deliberately deck-wide and search-oriented; it is not the fresh authoring read required in
539
+ step 3. Rebuild each mockup under your constraints
540
+ — the rebuild rule is owned by
541
+ `workflow/create.md` → Preconditions (reproduce the mockup's composition, hierarchy, graphic
542
+ mechanism, AND granularity — its organism count, badges, satellites, and annotation layers are
543
+ part of the target, and restraint is a colour budget, never an element budget; texts follow the
544
+ story). It never hard-fails: if it produces no mockups (exit 0 — the add-in can't generate them)
545
+ author from the storyboards alone. Skip it only for targeted work on slides that **already
546
+ exist** — an edit or a rework.
547
+ When storyboard objects share a `visualFamily`, rebuild those mockups as one recognizable visual
548
+ series. The lowest-numbered member is the anchor. Preserve its shape vocabulary, framing,
549
+ hierarchy, annotation style, illustration treatment, and spatial rhythm across the family, but
550
+ adapt every member's element count, sizing, arrangement, labels, emphasis, and connections to its
551
+ own complete `keyMessage`, `contentNotes`, role, and structure. Never copy another member's text,
552
+ claims, or data, never force its exact geometry, and never omit approved content because it does
553
+ not fit the anchor composition.
554
+ 2. **Execute `asset-plan.md` — search and fetch every unchecked item.** Discover the available
555
+ image engines by listing them — `slidemind ls engines --subtype image` (no PowerPoint window
556
+ needed where the add-in serves the pane-free engine routes) — judge which engine fits from its
557
+ label and description, then run every query in `asset-plan.md` and fetch the picks.
558
+ (`slidemind search` without `--engine` picks an image engine the same way.) Listing the engines
559
+ is discovery, not sourcing: this step is done only when every `asset-plan.md` item is checked
560
+ off with a downloaded filename or marked `(no result)` after its search actually ran. Four
561
+ mechanics that waste rounds when gotten wrong:
562
+ - **Icon results have no preview.** `slidemind view-slide` serves slide-library results only —
563
+ on an image/icon search it answers "no image returned" every time, so never call it there and
564
+ never retry it. Pick from the `search` output's titles/scores; a download is cheap and
565
+ `download-result` prints each asset's size + recolor info — download first, judge from the
566
+ saved file, re-search once if it was wrong. At most two search rounds per need; two failed
567
+ downloads = mark it `(no result)` and move on.
568
+ - **Batch the downloads:** one `download-result --search <id> --pick <n,n,…>` per search id —
569
+ never one call per icon.
570
+ - **Quote hex colors:** `--icon-color "#<hex>"` (a value resolved from a corporate-design.css token) — an unquoted `#` makes the shell drop the
571
+ rest of the line.
572
+ - Searches come **from the file, after the concept pass** — never from plan nouns before the
573
+ concepts exist. The engine
574
+ search/reuse mechanics live in **`slidemind-search`** — use it to find and fetch imagery; the
575
+ create-only detail — sizing a fetched asset's box and recolouring an icon — is in *Placing engine
576
+ imagery* below. To pull in an **existing whole slide** (not just an image), use
577
+ `slidemind-search`'s `add-slide` — it folds the slide into `decks/<slug>/slides/` as a native
578
+ `.pptx` that coexists with your JSX in play order and survives re-push. The slide can come from
579
+ an engine search **or** from a local `.pptx` on disk (`add-slide --from <file.pptx> --pick <n>
580
+ --deck <slug>`, host-free); both fold in identically — see `slidemind-search`.
581
+ 3. **Reopen the concepts, then author in small batches.** Once the searches and asset downloads are
582
+ complete, split a concept-seeded deck into batches of at most **3 slides**. For each batch, first
583
+ Read its matching anchored `decks/<slug>/concepts/concept-slide-NN.png` files together at full
584
+ detail; as the **very next tool action**, create those slides'
585
+ `decks/<slug>/slides/NN-<topic>.jsx` files. Put no search, command, reference read, user exchange,
586
+ or unrelated work between the concept images and the JSX write.
587
+ The deck-wide discovery read in step 1 never counts as this authoring read. A user interruption,
588
+ resumed turn, compaction, long wait, or unrelated tool work invalidates an earlier authoring read:
589
+ re-list `decks/<slug>/concepts/` if needed and reopen the affected anchored files before writing.
590
+ This batching is a local-harness context discipline, not a second create pass: the whole deck
591
+ remains one create pass and every slide file is created exactly once. Use a zero-padded numeric
592
+ prefix from the first file on (play order is filename order here; see the slide-file row in the
593
+ command mapping), one default export per slide, and one bundle layout (Mode A) or blank-content
594
+ layout with freeform children (Mode B), exactly as the bundle docs prescribe. **A slide whose
595
+ `asset-plan.md` section lists downloaded assets is UNFINISHED until its jsx references them**
596
+ (`<img src="./assets/engine-….svg">`, sized per *Placing engine imagery* below) — a concept full
597
+ of pictograms rendered as bare text boxes is a failed rebuild, not a style choice.
598
+ 4. **Look at your own draft first (you, the agent).** This is the **draft check** in
599
+ `workflow/build-and-export.md` — your pre-check, *before* any human sees the deck. Two rules
600
+ moved early on purpose — do them NOW, not at the review gate when the run is long and attention
601
+ is spent: first run `slidemind build <deck>` once and fix every `[lint:warn]` it prints (a
602
+ mechanical pass on files you just wrote); and after any fix round below, one more `slidemind
603
+ view-draft` over the changed slides is mandatory — the verification must appear in your command
604
+ sequence, not only in prose. Run `slidemind view-draft <deck>`: it renders each authored `slides/*.jsx` to a per-slide PNG and hands the
605
+ images back to you — **nothing is pushed, no `.pptx` is written, no review gate opens**. For
606
+ every concept-seeded slide, Read its anchored
607
+ `decks/<slug>/concepts/concept-slide-NN.png` and matching
608
+ `decks/<slug>/.draft-preview/<slide-basename>.png` **together in the same visual inspection**, in
609
+ batches of at most 3 pairs. Diff each pair organism by organism; a draft-only inspection does not
610
+ satisfy this check. Fix anything visibly wrong **in the JSX** (re-express, never delete), render
611
+ again, and reopen the affected anchored concept/draft pairs until each slide is sound. One round
612
+ usually suffices. It runs
613
+ locally against the materialized bundle, so it needs no awake pane and no open host once the
614
+ bundle has been downloaded once. Two faithful limits to know: a slide on a **purpose-built (Mode
615
+ A) layout** (cover/divider/agenda) and a **reused native `.pptx`** slide have no freeform region
616
+ to capture, so they come back as a status line, not an image — judge those at the full-deck
617
+ `review`/`build` step below. Do this self-check before the human review gate; don't push a draft
618
+ you haven't looked at.
619
+ 5. **The review gate — the moment the deck builds clean.** This is the **review gate** in
620
+ `workflow/build-and-export.md`; the CLI's gate command is `slidemind review <deck>`. Run it the
621
+ instant the authored set builds clean — before any deliver, without asking whether the user wants
622
+ a review. It builds the HTML preview first (the same lint the render enforces, so a gate that
623
+ *opens* is a clean build; while lint errors remain it exits non-zero — fix and re-run), then
624
+ opens the browser with a spatial comment overlay and **blocks until the user decides** (host-free
625
+ — no open PowerPoint needed for the gate). Announce it per *Two UX rules*: tell the user the
626
+ browser opened and give the clickable gate URL. **Blocking is the point: give the shell call a
627
+ generous timeout (the gate waits up to 30 min) and let it sit — a long quiet wait means the user
628
+ is reviewing, not that something hung. Never cancel it; if your harness kills the call early,
629
+ just re-run it (the user's open tab reconnects).** The verdict prints to stdout:
630
+ - `DECISION: approved` → proceed to the deliver the user chose at intake: `slidemind push <deck>`
631
+ (into PowerPoint) or `slidemind build-pptx <deck>` (to a file).
632
+ - `DECISION: comments` → the user left spatially-anchored notes, each citing a
633
+ `slides/<file>.jsx:line:col`, the source line, the click position, and a **round tag** (`[2,
634
+ round 1] …`) — plus a readonly-layout note where the click landed on a layout slot. A pin
635
+ carrying an *older* round was dropped on the previous render, so read the file before you edit
636
+ it rather than trusting the cited line blindly. **Edit the cited files in place at the given
637
+ line and re-run `slidemind review <deck>` in the same turn.** **Expect several consecutive
638
+ `DECISION: comments` rounds — that is the normal shape of a review, not an error.** The user's
639
+ tab waits while you fix (browsing stays live, pinning is off) and refreshes with your next run,
640
+ which blocks until they send the next batch of pins or approve. So never end your turn on a
641
+ comments round, never claim to be "polling", and never send the user back to the browser
642
+ between rounds — nothing reaches them until the gate runs again. Addressed pins come back as read-only ghost pins so the user can
643
+ confirm each note was worked in. Only `DECISION: approved` or `DECISION: pending` ends the
644
+ loop. Nothing is exported on a comments round. **Every round is persisted verbatim in
645
+ `<deck>/review.json`** — if your shell capture of the gate's output was truncated or lost
646
+ (backgrounded command, clipped scrollback), read that file for the complete comment list; never
647
+ guess at missing comments or ask the user to re-type them.
648
+ - `DECISION: pending` → the gate timed out with no answer (the user stepped away). Not approval,
649
+ not rejection — **do not deliver**. Wrap up your turn: tell the user the preview is still
650
+ waiting for their review and that on their go-ahead you'll re-run `slidemind review <deck>`
651
+ (their tab reconnects).
652
+
653
+ `slidemind review` is the only step that pauses; `push`/`build-pptx` never pause — they render
654
+ pane-free (local capture + server-side assembly, with live per-slide progress). **CLI exports
655
+ happen out of the user's sight, so the flow invariant — *the user sees every change before the
656
+ task is done* — makes re-review mandatory here: every deliver is preceded by an approved review
657
+ of exactly what it delivers. After any later slide change, the deck re-enters `slidemind review`
658
+ before it can be pushed or exported again — never deliver an unreviewed change.** If several
659
+ presentations are open, confirm **which one to push into** first (it can differ from the design
660
+ source `slidemind ready` locked in). After approval, run the push without asking; it works while
661
+ PowerPoint is backgrounded, and the CLI itself waits + retries if the pane is needed (see *First
662
+ step* above). If a push still times out, the rendered `.pptx` is saved next to the deck — re-run
663
+ `push` after the user clicks the pane, without rebuilding.
664
+
665
+ **On a clean approve + deliver, the task is done.** Report what landed (slide count + target) and
666
+ stop — no sanity pass, no re-verification. The visual QA already happened at the draft check
667
+ (step 4) and the user signed off at the review gate.
165
668
 
166
669
  ## Manual PowerPoint edits (the reconcile loop)
167
670
 
168
- The user may have edited the deck directly in PowerPoint since your last deliver — moved a shape, retyped a line, recoloured a box. Those edits live only in that file or that window; the deck's jsx knows nothing about them. `slidemind build-pptx` and `slidemind push --replace` therefore check before they write, and play the changes back to you:
671
+ The user may have edited the deck directly in PowerPoint since your last deliver — moved a shape,
672
+ retyped a line, recoloured a box. Those edits live only in that file or that window; the deck's jsx
673
+ knows nothing about them. `slidemind build-pptx` and `slidemind push --replace` therefore check
674
+ before they write, and play the changes back to you:
169
675
 
170
- - **Plain text edits are already folded into your jsx** — the command prints `note: folded N manual text edit(s) … into slides/<file>` and the fold is now the source of truth on disk. **Re-read that file before your next edit** or you will write over it from a stale copy.
171
- - **Everything else refuses the deliver** with a `RECONCILE REQUIRED` report per slide (geometry in EMU, style changes, added/removed shapes) and exit code non-zero. Nothing was written or pushed.
676
+ - **Plain text edits are already folded into your jsx** — the command prints `note: folded N manual
677
+ text edit(s) … into slides/<file>` and the fold is now the source of truth on disk. **Re-read that
678
+ file before your next edit** or you will write over it from a stale copy.
679
+ - **Everything else refuses the deliver** with a `RECONCILE REQUIRED` report per slide (geometry in
680
+ EMU, style changes, added/removed shapes) and exit code non-zero. Nothing was written or pushed.
172
681
 
173
682
  On a `RECONCILE REQUIRED`:
174
683
 
175
- 1. **Fold every listed change into the slide's jsx** — the user made them on purpose; losing them is unacceptable. Translate geometry deltas into **layout intent** (spacing, order, relative sizing, which region a thing sits in) — never literal offsets, absolute coordinates, or transform/translate hacks bolted onto a working composition. Recreate added shapes as jsx elements; drop deleted ones. If a folded position genuinely cannot fit the content area, re-express its intent (reflow, reorder, resize) rather than discarding it.
176
- 2. Lines marked `[preserved]` are foreign add-in content (e.g. an embedded chart) — do **not** recreate them; they are spliced back into the rendered slide automatically.
177
- 3. **Re-run the same command.** The re-run proceeds: the report was acknowledged (`decks/<slug>/.reconcile-ack.json`), and only a NEW manual edit re-arms the check. The deck changed, so the flow invariant applies — re-run `slidemind review <deck>` before delivering again.
178
- 4. **Do this silently.** Reconcile is bookkeeping, not a deliverable: never explain the report, the baseline, or your folding steps, and never ask the user about it. Fold and carry on with their actual request in the same turn. At most one short clause in your final answer ("kept your manual layout change").
179
-
180
- `--force` on either command **discards the user's manual edits** and writes anyway. It is a last resort, only on the user's explicit say-so — never reach for it to get past a report you could fold.
684
+ 1. **Fold every listed change into the slide's jsx** — the user made them on purpose; losing them is
685
+ unacceptable. Translate geometry deltas into **layout intent** (spacing, order, relative sizing,
686
+ which region a thing sits in) — never literal offsets, absolute coordinates, or
687
+ transform/translate hacks bolted onto a working composition. Recreate added shapes as jsx
688
+ elements; drop deleted ones. If a folded position genuinely cannot fit the content area,
689
+ re-express its intent (reflow, reorder, resize) rather than discarding it.
690
+ 2. Lines marked `[preserved]` are foreign add-in content (e.g. an embedded chart) — do **not**
691
+ recreate them; they are spliced back into the rendered slide automatically.
692
+ 3. **Re-run the same command.** The re-run proceeds: the report was acknowledged
693
+ (`decks/<slug>/.reconcile-ack.json`), and only a NEW manual edit re-arms the check. The deck
694
+ changed, so the flow invariant applies — re-run `slidemind review <deck>` before delivering
695
+ again.
696
+ 4. **Do this silently.** Reconcile is bookkeeping, not a deliverable: never explain the report, the
697
+ baseline, or your folding steps, and never ask the user about it. Fold and carry on with their
698
+ actual request in the same turn. At most one short clause in your final answer ("kept your manual
699
+ layout change").
700
+
701
+ `--force` on either command **discards the user's manual edits** and writes anyway. It is a last
702
+ resort, only on the user's explicit say-so — never reach for it to get past a report you could fold.
181
703
 
182
704
  Three refusals are not foldable and need the user, not a retry:
183
705
 
184
- - `the live deck contains N slide(s) not in this deck` — a whole-deck replace would delete slides someone added by hand or with another tool. Push **without** `--replace` to insert instead, or ask the user what should happen to them.
185
- - `<file> was edited in PowerPoint …` naming slides with no jsx behind them (a reused native slide, or one pushed by another deck) — build to a different target with `--out <other file>` so their edits survive, or ask.
186
- - `backend does not support manual-edit reconcile` / `the live deck could not be inspected` — the add-in is older than this contract, or its PowerPoint build cannot export slides. Tell the user to update the slidemind add-in. Do not paper over it with `--force`.
706
+ - `the live deck contains N slide(s) not in this deck` — a whole-deck replace would delete slides
707
+ someone added by hand or with another tool. Push **without** `--replace` to insert instead, or ask
708
+ the user what should happen to them.
709
+ - `<file> was edited in PowerPoint …` naming slides with no jsx behind them (a reused native slide,
710
+ or one pushed by another deck) — build to a different target with `--out <other file>` so their
711
+ edits survive, or ask.
712
+ - `backend does not support manual-edit reconcile` / `the live deck could not be inspected` — the
713
+ add-in is older than this contract, or its PowerPoint build cannot export slides. Tell the user to
714
+ update the slidemind add-in. Do not paper over it with `--force`.
715
+
716
+ ## Charts (create-authoring specifics)
717
+
718
+ A real series of numbers is a `<Chart>` element in your JSX — one self-closing element that renders
719
+ as a native PowerPoint chart with its own embedded workbook, so the client double-clicks it and
720
+ edits the data in Excel. Never hand-draw a chart from divs, bars, lines or SVG, and never let a
721
+ table stand in for one; conceptual figures (process, framework, hub, timeline with no measured
722
+ values) are not charts and stay HTML/SVG. The type list, the props each type accepts, the
723
+ theme-first colour rule (leave `seriesStyle` off and the brand paints it) and the kinds that are
724
+ out of the model live in the bundle's `workflow/authoring.md` → Charts — read them there, don't
725
+ guess; the composition rule (one chart is the hero; the accent marks ONE series or point, not six)
726
+ is in `workflow/composition.md` → Charts in the composition. Three local-harness facts: numbers the
727
+ user states in chat go straight into the chart's `data` prop; this harness has **no analyst
728
+ subagent**, so when the numbers live in a file you do the aggregation yourself, say what you did,
729
+ and put the RESULT in the props (the deck carries the numbers, never a pointer to your workspace);
730
+ and both the HTML preview and `slidemind view-draft` paint a **stand-in** for a chart, not
731
+ PowerPoint's render — judge a chart's final look from the pushed slide (the review gate warns the
732
+ user on chart slides itself). Editing a chart later — yours, or one on a slide
733
+ the deck adopted from PowerPoint — is editing its `<Chart>` props and re-rendering; an adopted
734
+ chart keeps its `data-sm-source-id` and its `conversions/<stem>.slide.pptx` (never delete either:
735
+ the push patches the client's own chart part through them, so its Excel data and styling
736
+ survive). To see what a chart on a live slide plots, `slidemind read <presId> --mode raw` prints a
737
+ data table per chart; `slidemind read <file.pptx>` (host-free) reports text only, no chart data.
187
738
 
188
739
  ## Placing engine imagery (create-authoring specifics)
189
740
 
190
- Finding and fetching engine imagery is `slidemind-search`'s job (`slidemind search` → `slidemind download-result`). What follows is **create-only**: how to size and colour a fetched asset so it reads on-brand in your JSX, honoured in both the `slidemind build` preview and the render.
191
-
192
- 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):
193
-
194
- - **Size the box from the asset's own dimensions.** Both `slidemind search` (from the engine index, before any fetch) and `slidemind download-result` (measured from the delivered bytes) print each image's intrinsic `width×height`. **Use it.** A plain `<img>` is stretched to whatever box you write, so a box whose aspect ratio disagrees with the asset ships a distorted picture. Derive one side from your layout and compute the other from the printed ratio. `object-fit: contain`/`cover` is honoured in the render as well as the preview, but it is a *fallback*, not a substitute: it converts a wrong ratio into letterboxing or a crop, both of which you chose blind. When the size prints as `(size unknown)`, the format carried no readable header — give the asset a square-ish box and check it at the draft check.
195
- - **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.
741
+ Finding and fetching engine imagery is `slidemind-search`'s job (`slidemind search` → `slidemind
742
+ download-result`). What follows is **create-only**: how to size and colour a fetched asset so it
743
+ reads on-brand in your JSX, honoured in both the `slidemind build` preview and the render.
744
+
745
+ Engine results land as files referenced with `<img src="./assets/<file>">`. These facts are specific
746
+ to the local harness (the bundle's `workflow/*.md` stay harness-neutral):
747
+
748
+ - **Size the box from the asset's own dimensions.** Both `slidemind search` (from the engine index,
749
+ before any fetch) and `slidemind download-result` (measured from the delivered bytes) print each
750
+ image's intrinsic `width×height`. **Use it.** A plain `<img>` is stretched to whatever box you
751
+ write, so a box whose aspect ratio disagrees with the asset ships a distorted picture. Derive one
752
+ side from your layout and compute the other from the printed ratio. `object-fit: contain`/`cover`
753
+ is honoured in the render as well as the preview, but it is a *fallback*, not a substitute: it
754
+ converts a wrong ratio into letterboxing or a crop, both of which you chose blind. When the size
755
+ prints as `(size unknown)`, the format carried no readable header — give the asset a square-ish
756
+ box and check it at the draft check.
757
+ - **Never open the SVG to find out whether it recolours.** `slidemind download-result` prints a
758
+ `recolor` descriptor for each asset — `{ recolorable, mode, applied, note }`, where `mode` is
759
+ `currentColor`, `mono`, `multicolor`, or `raster`. Read it; that *is* the answer.
196
760
  - **Two ways to colour an icon, both honoured in the `slidemind build` preview *and* the render:**
197
- - **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. The tint is applied by the add-in, so on the window-free path it can be **refused**: the asset is then saved in its original colours and the `recolor` note says so. Believe the note over your request — to actually bake the colour in, re-run the search and the download with `--to <presId>` against an open PowerPoint window.
198
- - **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.
199
- - **Batch the fetch.** Pull every icon a slide needs in one call — `slidemind download-result --search <id> --pick <n,n,…> --deck <deck> [--icon-color <hex,hex,…>]` (one colour applies to all picks, or give one per pick; add `--to <presId>` only on an add-in that still relays the fetch through a pane, which the `search` output names) — the downloads run concurrently. Don't run `download-result` once per icon.
761
+ - **Bake it in (prefer this):** pass `--icon-color <hex>` — a hex you resolve from a token in the
762
+ bundle's `corporate-design.css` — to `slidemind download-result`. Works for any `recolorable`
763
+ glyph and the colour is in the saved file, so preview and render always agree. The tint is
764
+ applied by the add-in, so on the window-free path it can be **refused**: the asset is then saved
765
+ in its original colours and the `recolor` note says so. Believe the note over your request — to
766
+ actually bake the colour in, re-run the search and the download with `--to <presId>` against an
767
+ open PowerPoint window.
768
+ - **Tint via CSS:** set `color` to a token on the `<img>`. This works only for `mode:
769
+ "currentColor"` icons (the preview inlines the SVG so `color` resolves, and the render
770
+ substitutes `currentColor`). A `mono` icon will not respond to CSS colour — bake it instead.
771
+ - **Batch the fetch.** Pull every icon a slide needs in one call — `slidemind download-result
772
+ --search <id> --pick <n,n,…> --deck <deck> [--icon-color <hex,hex,…>]` (one colour applies to all
773
+ picks, or give one per pick; add `--to <presId>` only on an add-in that still relays the fetch
774
+ through a pane, which the `search` output names) — the downloads run concurrently. Don't run
775
+ `download-result` once per icon.
200
776
 
201
777
  ## Command mapping (the workflow vocabulary ⇄ your CLI)
202
778
 
203
- 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:
779
+ The bundle's `workflow/*.md` speak the harness-neutral verbs defined in `workflow/flow.md` →
780
+ Vocabulary. You are the local harness — this is your mapping:
204
781
 
205
782
  | Verb (`workflow/flow.md`) | Your equivalent (local harness) |
206
783
  |---|---|
207
784
  | (session setup — a CLI-only stage before the spine) | `slidemind ready [deck]` — the one-shot session start: connection ladder + design resolution (open window, the deck's own binding, or `--brand <presFP>`) + 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 |
208
785
  | **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) |
209
- | **clarify** / **plan sign-off** | intake stays in chat with the user (above); for decks, persist `decks/<slug>/plan.md` as `## Red thread` + `## Per-slide storyboards` (one `storyboard-canvas` JSON block per slide), then run `slidemind plan <deck>` — the same blocking `DECISION:` gate contract as `slidemind review`, on the plan (renders editable storyboards — red-thread strip + spatial canvases — plus slide-anchored comments; expect several comment rounds, some returning instantly with comments queued while you revised; loop until approved) |
210
- | concept mockups (mandatory deck stage, after plan sign-off) | `slidemind concepts <deck>` — renders one image mockup per approved-plan slide into `decks/<slug>/concepts/concept-slide-NN.png`; the local-harness stand-in for the in-app manager's *unconditional* concept pass on every full-deck delegation (`approvedPlan && !targetSlideScope`). **Read each and rebuild it** toward its target under your constraints (rule owned by `workflow/create.md` → Preconditions — don't restate it). It never hard-fails: on an empty result (exit 0 — the add-in can't generate them) author from the storyboards alone, but for a deck you always run it. Skip only where the add-in's `!targetSlideScope` gate would — a single slide, a tiny in-chat set, or a targeted rework of existing slides |
786
+ | **clarify** / **plan sign-off** | intake stays in chat with the user (above); for every from-scratch request — one slide included — persist `decks/<slug>/plan.md` as `## Red thread` + `## Per-slide storyboards` (one `storyboard-canvas` JSON block per slide), then run `slidemind plan <deck>` — the same blocking `DECISION:` gate contract as `slidemind review`, on the plan (renders editable storyboards — red-thread strip + spatial canvases — plus slide-anchored comments; expect several comment rounds; loop until approved) |
787
+ | concept mockups (mandatory for every from-scratch set, after plan sign-off) | `slidemind concepts <deck>` — renders one image mockup per approved-plan slide into the durable repo-relative path `decks/<slug>/concepts/concept-slide-NN.png`; immediately Read all of them for image/content search, then after searches reopen them in batches of at most 3 immediately before writing the matching `NN-*.jsx`. Re-list and reopen those paths after any interruption or continuation; never rely on an earlier chat image. The rebuild rule is owned by `workflow/create.md` → Preconditions. It never hard-fails: on an empty result (exit 0 — the add-in can't generate them) author from the storyboards alone, but for anything authored from a plan — one slide included — you always run it. Skip only for targeted work on slides that already exist (edit/rework) |
211
788
  | **read** / **list** the workspace | read the files from the materialized bundle dir (`<bundle>/…`) and your `decks/<slug>/` |
212
- | **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 |
213
- | 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) |
214
- | **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 |
789
+ | **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. For a concept-seeded create or structural rewrite, the immediately preceding tool action must Read the matching anchored concept path(s) at full detail |
790
+ | **draft check** | `slidemind view-draft <deck>` — renders each `slides/*.jsx` to `decks/<slug>/.draft-preview/<slide-basename>.png` and returns the images to **you**; **no push, no `.pptx`, no review gate**. Read each concept/draft path pair together, fix the JSX, render, and pair again. A draft-only inspection does not count. 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 |
215
791
  | **build & push** | `slidemind push <deck>` (into the open PowerPoint — the insert needs a window) · `slidemind build-pptx <deck> [--out <file>]` (to a `.pptx` file — **host-free** for a bound deck: no PowerPoint window at all) — deliver whichever target was locked at intake; both render server-side via the bridge and for a bound deck the render itself is pane-free |
216
- | **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` + the round it was dropped on). On approve → deliver (`slidemind push` / `build-pptx`); on comments → edit the cited files and re-run `slidemind review` in the same turn (addressed pins show as ghost pins); expect several comment rounds, some returning instantly with pins the user queued while you were fixing. 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. |
792
+ | **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` + the round it was dropped on). On approve → deliver (`slidemind push` / `build-pptx`); on comments → edit the cited files and re-run `slidemind review` in the same turn (addressed pins show as ghost pins); the user pins as many comments as they like and sends them as one batch (Approve is off while unsent pins exist); expect several comment rounds. 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. |
217
793
  | **inspect the deck** | `slidemind read [presId\|file.pptx] [--mode summary\|raw]` — one verb, two sources: pull the current content of an open presentation (a presId; **host-required** — it reads the live, possibly unsaved file) **or** read a local `.pptx` on disk (a file path; host-free — no PowerPoint, no pairing). Prefer the file path when the deck is saved. `summary` = per-slide outline; `raw` = each slide's plain text — to inspect what's there before editing. Plain text, not authoring markup |
218
794
  | **discover engines** (`list_engines`) | `slidemind ls engines [--type <collection\|search\|scope>] [--subtype <image\|slide\|template\|content>]` — the live catalog is the only engine list (the bundle carries none); pick an `id` from it, never guess one. Needs no PowerPoint window where the add-in serves the pane-free engine routes. It also lists **search scopes** for unfiltered corpus search — those belong to `slidemind-search`, not to imagery |
219
795
  | **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 asset in your JSX, size its box from the printed `width×height`, pass `--icon-color` / batch with `--pick <n,n,…>` and colour per *Placing engine imagery* below |
796
+ | **generate an image** | `slidemind imagen "<prompt>" --deck <deck> [--out <name.png>] [--size <size>] [--quality <tier>]` — use only for a planned photograph or illustration when engine sourcing returned nothing; never generate pictograms |
220
797
  | **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 |
221
798
 
222
- 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.
799
+ Everything else in `workflow/*.md` — the composition craft, the substrate/authoring rules, the
800
+ layout discovery and slot/working-area rules, the visual quality bar (applied at the draft check) —
801
+ applies to you unchanged.
223
802
 
224
803
  ## The brand and the workflow both live in the bundle, not here
225
804
 
226
- Do not restate brand values (colour, type scale, spacing, layout names, accent discipline) or re-derive the authoring/composition craft in this file or in slide files — they are in the bundle's `design.md` and `workflow/*.md`. Read them and follow them. Don't load external UI/design-taste plugins during slide work; compose against the bundle's layouts and tokens. If the corporate design moves mid-task (`bundle_etag_stale`), the CLI self-heals: it refreshes the bundle and retries the render on its own — afterwards re-read the bundle's `design.md` before authoring anything new, since the rules may have changed.
805
+ Do not restate brand values (colour, type scale, spacing, layout names, accent discipline) or
806
+ re-derive the authoring/composition craft in this file or in slide files — they are in the bundle's
807
+ `design.md` and `workflow/*.md`. Read them and follow them. Don't load external UI/design-taste
808
+ plugins during slide work; compose against the bundle's layouts and tokens. If the corporate design
809
+ moves mid-task (`bundle_etag_stale`), the CLI self-heals: it refreshes the bundle and retries the
810
+ render on its own — afterwards re-read the bundle's `design.md` before authoring anything new, since
811
+ the rules may have changed.
227
812
 
228
813
  ## Failure modes the render lint can't catch
229
814
 
230
- 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:
815
+ Render-time lint rejects contract violations (unsupported CSS, bad imports, remote `<img>` URLs —
816
+ the add-in's capability-table engine; `slidemind build` runs the same engine locally from the
817
+ bundle). It can't catch content-shaped failures; check for these **at the draft check** (step 4,
818
+ before the review gate) — not after delivery:
231
819
 
232
820
  - Layout-default / placeholder text leaking through an unfilled prop.
233
821
  - A bullet list standing in for a structured idea (process, comparison, timeline).
@@ -239,4 +827,7 @@ Render-time lint rejects contract violations (unsupported CSS, bad imports, remo
239
827
 
240
828
  ## Where the deck lives
241
829
 
242
- `decks/<slug>/` is created in the **current working directory** (the shell's pwd when the skill was invoked). Every `slidemind` command and `mkdir` resolves `decks/` against that cwd — don't `cd` into the skill's install directory. The materialized bundle lives in the cache dir above, not under the deck.
830
+ `decks/<slug>/` is created in the **current working directory** (the shell's pwd when the skill was
831
+ invoked). Every `slidemind` command and `mkdir` resolves `decks/` against that cwd — don't `cd` into
832
+ the skill's install directory. The materialized bundle lives in the cache dir above, not under the
833
+ deck.