zynkr-slide · diff
git:20260906.8f8cc55 to git:20260918.2429d96
15 added, 0 removed. Audit A to A.
---
name: zynkr-slide
sheetId: "1.24"
description: "The conductor of the slide relay (sitting above the three-stage relay): fires when the user says '做一份簡報/做個 deck/幫我把這些做成投影片/做季報簡報/all-hands 簡報/deep dive 簡報/pitch deck'. I do a one-shot intelligent intake — detecting which kind of deck this is (deep-dive / business-review / data-presentation / all-hands / planning / pitch / update / teach / fundraise), taking stock of the material and storyline the user has already given, proposing a page count for the user to confirm, and gathering the must-include material and mode — then assembling a SLIDE_PACKET ▸ Brief and driving slide-storyline-designer → slide-page-splitter → slide-visual-selector → the slide-pptx skill in sequence to render the .pptx. Defaults to express mode (ask everything up front once, only asking the user to sign off at two points: storyline finalization and final file); pass the guided parameter to retain each stage's own per-stage human review. Scope boundary: I only do intent detection, context convergence, ▸ Brief injection, and relay orchestration; I don't lay out the narrative arc, split pages, choose layouts, or render the .pptx myself — those belong to the three stages and the slide-pptx skill respectively. In addition, if the user gives a fixed template (charter / one-page QBR / an existing deck to be re-skinned) or asks for a deliverable that maps onto the template library, I take the template-fill branch (copy template → extract content → fill fixed fields → recolor external templates to Zynkr brand colors by default) instead of the three-stage relay."
category: brand-marketing
project: zynkr-slide
platform: claude
status: Done
author: Peter Tu
input: "Raw slide material / topic + the message you want to convey (scattered notes, bullets, an old deck, data, or verbal key points all work), optionally with cues about the deck's purpose; or an existing ▸ Storyline / ▸ Pages you want to continue from. Parameter: express (default) / guided."
process: "Detect intent + take stock of existing context → single intelligent intake (confirm purpose, audience/occasion, proposed page count, must-include material, mode) → load the use-case playbook to assemble the SLIDE_PACKET ▸ Brief → create a shared working subfolder to store the ▸ Brief → drive the three-stage relay in sequence (carrying the ▸ Brief) → hand ▸ Visuals to the slide-pptx skill to render → deliver the .pptx"
output: "A finished .pptx (produced via the three-stage relay + pptx-skill rendering), plus the complete SLIDE_PACKET (▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals) stored in the same working subfolder."
synergy: ["slide-storyline-designer", "slide-page-splitter", "slide-visual-selector", "slide-pptx"]
handoff: ["slide-storyline-designer", "slide-page-splitter", "slide-visual-selector", "slide-pptx"]
executed_by: internal-user
+ house-style: bound
+
---
# zynkr-slide
```bash
npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill zynkr-slide
```
## What this is
`zynkr-slide` is the **conductor** of the slide relay, sitting **above** the three-stage relay. The full chain is:
```
zynkr-slide ← you are here (conductor)
│ one intake → SLIDE_PACKET ▸ Brief (deck purpose / audience & occasion / working subfolder / page budget / must-include material / mode / brand application / per-stage emphasis)
▼
slide-storyline-designer (1.25)
│ SLIDE_PACKET ▸ Storyline
▼
slide-page-splitter (1.26)
│ SLIDE_PACKET ▸ Pages
▼
slide-visual-selector (1.27)
│ SLIDE_PACKET ▸ Visuals (render-ready)
▼
slide-pptx skill → renders into a .pptx
```
**Core idea**: The three-stage relay is already quite complete on its own, but it has two gaps — (1) **four cold starts**: each stage opens by re-asking the user for context it can't infer; (2) **the whole deck has no shared understanding of "what kind of deck this is"**, so the same generic rules get applied to both a deep dive and an all-hands — the deep dive isn't deep enough and the all-hands is too dense. `zynkr-slide` fills these two gaps: **ask once** (collapse the four cold starts into a single intelligent intake), and load a playbook based on the "deck purpose" to assemble a `SLIDE_PACKET ▸ Brief` that gets injected all the way down, so every stage knows "what kind of deck this is and which direction to push."
**What it eats**: raw material / topic + the message you want to convey (no matter how messy), optionally with purpose cues; or an existing ▸ Storyline / ▸ Pages you want to continue from.
**What it produces**: a finished `.pptx`, plus the complete `SLIDE_PACKET` (▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals) stored in the same working subfolder.
**What it does NOT produce**: I do **not** lay out the narrative arc, split pages, choose layouts, or render the `.pptx` myself. I am a **thin orchestration layer** — detect intent, converge context, assemble the ▸ Brief, and drive the three stages and the slide-pptx skill in order (see ## Limitations). Each stage's professional judgment is still made by that stage itself.
> Whether the user fires me directly by shouting "make a deck" or gets routed in via `/zynkr-skills`, the behavior is identical — both entry points run the same intake → ▸ Brief → relay.
---
## Resources you'll use
- **Use-case playbook (the knowledge core of this skill)**: `./references/use-case-playbooks.md` — the lookup table for "what kind of deck this is → which preset to use." Each purpose gives: detection cues, the mapped storyline `occasion` enum, narrative-skeleton bias, page-budget range, default information density, and **per-stage emphasis directives**. Read it both at Step 1 when detecting purpose and at Step 3 when assembling the ▸ Brief.
- **Brand visual/tone source (config)**: `./references/brand-source.md` — this skill **does not bundle brand content**; this file configures where to load the brand spec from, and ships a generic schema. Load per this file during intake and ▸ Brief assembly; if unset, fall back to neutral defaults and tell the user "brand not applied." Each of the three stages also loads its own brand-source again; this layer is only responsible for carrying the "use brand" intent into the ▸ Brief.
- **Template source (config)**: `./references/template-source.md` — configures the Drive template-library location (the SOT template folder), how templates are tagged to a use-case (`TEMPLATE-INDEX`), and the field manifest for each template. The **template-fill branch** reads it at Step 1/2 when detecting and selecting a template; if unset/unreadable, ask the user to paste the template link directly.
- **Downstream three stages (relay chain)**: `slide-storyline-designer` (stage 1), `slide-page-splitter` (stage 2), `slide-visual-selector` (stage 3). Call them stage by stage via the **Skill tool**, letting each stage read its own SKILL.md and run its own logic; I only pass the ▸ Brief and the previous stage's handoff packet, and **do not rewrite its steps**. All three stages already have the hook "if a ▸ Brief is present, obey its directives."
- **Render skill (already installed)**: the slide-pptx skill at `~/.claude/skills/slide-pptx/`, called by stage 3 once ▸ Visuals is finalized, via **Create from scratch** (`Read ~/.claude/skills/slide-pptx/pptxgenjs.md`). This skill does **not** vendor or rewrite slide-pptx.
---
## Step 1 — Detect intent + take stock of existing context
Before asking anything, take stock first, and **do not re-ask for what the user has already given** (this is exactly the value of this skill).
1. **Determine the relay entry point**: does the user already have a relay artifact in hand?
- Already pasted/saved `▸ Visuals` → go straight to slide-pptx rendering (end of Step 4).
- Already has `▸ Pages` → continue from stage 3.
- Already has `▸ Storyline` → continue from stage 2.
- Only raw material / topic → start from stage 1 (most common).
- **The user gave/specified a fixed template** → **skip the three-stage relay**, take the **template-fill branch (Step 4-T)**: pasted a Slides/PPTX template link and wants to "use this layout," or requested a deliverable that maps onto `TEMPLATE-INDEX` (such as charter / one-page QBR / an existing deck to be re-skinned).
- **How to detect template-fill**: any one of these holds → it's template-fill — (a) the user pasted a template link and said "use this format / apply this layout"; (b) the requested deliverable name maps onto a use-case key in the template library; (c) the source is the combination of a **content document** (Doc/notes) + a **fixed output layout**. **If unsure, ask one question at Step 2**: "Do you want me to **fill a fixed template**, or **design the narrative from scratch**?" **Don't default to the three stages** (this is exactly the lesson from last time).
- **Still assemble a complete ▸ Brief when continuing mid-stream**: confirm the purpose first, then load from the playbook the per-stage emphasis directives **for the stages that will actually run next** (together with audience & occasion, must-include material, and brand application) — you can't just put purpose + mode + page budget, otherwise the later stages won't get that purpose's "flavor," which is the same as not applying the orchestrator at all. Fields for already-completed stages can be summarized briefly. If the artifact you're continuing from wasn't originally produced from a ▸ Brief and has no purpose cue, run a quick intake round (confirm purpose/mode/page budget/save location) before proceeding — don't silently guess a purpose that might contradict the existing content.
2. **Detect the deck purpose**: read the "detection cues" in `./references/use-case-playbooks.md` and map the user's wording/situation onto one purpose (deep-dive / business-review / data-presentation / all-hands / planning / pitch / update / teach / fundraise). If unsure, let the user choose at Step 2 — **don't force a guess**.
3. **Take stock of the fields already given**: has the user already stated audience, occasion, page-count ideas, the must-include data/cases, whether to apply branding? Note down what's given; at Step 2 only ask for **what's still missing**.
Tell the user your read in one sentence so they can correct it:
> "Looks like a **<purpose>** deck, starting the relay from **<entry point>**. Let me confirm a few things and then I'll get going."
---
## Step 2 — Single intelligent intake (HITL: ask once)
Ask for **all** the missing context **in one shot** (don't pull teeth one question at a time). Use `AskUserQuestion` to turn discrete options into menus, and ask open fields as free text. Clear it all in one round:
1. **Confirm purpose**: present the purpose detected at Step 1 for the user to confirm/change (the menu carries the playbook's 9 purposes, plus a "none of these / not sure" option). If they pick "none of these / not sure," take the playbook's **no-match fallback**: use the generic skeleton of the "mapped occasion," and write the per-stage emphasis as "occasion default, no extra flavor."
2. **Audience & occasion**: who's the audience? The occasion maps onto storyline's existing enum (**external pitch / internal update / teaching & training / fundraise**) — the playbook already gives each purpose's suggested mapping; here, let the user confirm/change it.
3. **Proposed page count (page budget)**: **proactively compute a suggested range** for the user to confirm — don't make them imagine it. Suggestion = the playbook's page-budget range ⨉ a material-volume nudge (lots of material → top of the range, little material → bottom). Make clear this is a **target, not a hard cap**; how many pages actually get cut is stage 2's call.
4. **Must-include material**: is there any data/case/message/page that "absolutely has to go in"? If none, note "none."
5. **Save location**: where should this deck's working subfolder be created? (Subsequent ▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals and the .pptx all go here.)
6. **Mode**: `express` (default — ask everything up front, only sign off at two points: storyline finalization and final file) or `guided` (retains each stage's own per-stage review)? If the user launched with the `guided` parameter, use guided; otherwise express.
7. **Brand & visual treatment**: load the brand per `./references/brand-source.md`? If it can't load, state plainly that we go with neutral defaults. **If this is the template-fill branch and the template is external (not an existing Zynkr brand asset) → default = apply brand (recolor)**, the deliverable should be in Zynkr colors rather than the template's original colors; ask the visual treatment in one extra question: **recolor (change to Zynkr brand colors, default) / keep (leave the template as-is, e.g. when the template is already Zynkr brand) / hybrid (keep the layout, swap only the key colors + fonts)**. Don't backfill branding halfway through.
8. **Template selection (template-fill branch only)**: if the user brought their own template link → use it; otherwise read `TEMPLATE-INDEX` per `./references/template-source.md`, match it against the use-case detected at Step 1, and **propose 1–2 candidates for the user to confirm**. If no match → ask the user to paste a link, or fall back to the three-stage relay.
> **On-the-spot check of must-include material vs page budget**: if the count of "must-include material" clearly blows past the top of the page budget (e.g. 10 data pages that absolutely must go in but only 8–12 pages given), raise the trade-off on the spot: raise the budget, or split into two decks — don't let content quietly get cut later or the budget quietly overflow.
> Asking everything in one shot is a hard rule. After intake ends, in express mode you **no longer interrupt the user to gather context** mid-stream (you only stop at storyline finalization and final file).
---
## Step 3 — Load the playbook + assemble SLIDE_PACKET ▸ Brief
Based on the confirmed purpose, take that cell's directives from `./references/use-case-playbooks.md` and assemble the ▸ Brief. **Per-stage emphasis** must be copied as concrete text from the playbook (not vague phrasing like "push a bit harder"), so each stage can act on it as soon as it receives it. The ▸ Brief's own field names are part of the relay contract — the three-stage hooks read them verbatim, so **do not rename them** (the one exception: `audience & occasion` is deliberately renamed by stage 1 and filled into its own "audience & situation" field — that's a field bridge between two different artifacts and is expected behavior):
```
SLIDE_PACKET ▸ Brief
────────────────────────────────────────
簡報用途 (use-case):
<deep-dive / business-review / data-presentation / all-hands / planning / pitch / update / teach / fundraise>
受眾與場合:
聽眾:<who they are>
場合:<對外提案 / 內部更新 / 教學培訓 / 募資> ← aligned to storyline's existing enum; mapped from purpose, confirmed by the user
工作子資料夾 (working-folder):
<absolute path of this deck's working subfolder (the save location asked at Step 2); ▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals and the .pptx all go here>
頁數預算 (page budget):
<target range, e.g. 12–15; target not hard cap, actual page cutting decided by stage 2>
必含素材 (must-include):
<content/data/cases/pages the user named as absolutely required; if none, write "無">
模式 (mode):
<express | guided>
套用品牌:
<yes, load per each stage's brand-source / no, neutral default>
逐棒強調 ▸ 故事線 (棒1):<copy from playbook: narrative-skeleton bias + which logic checks to weight + closing requirement>
逐棒強調 ▸ 分頁 (棒2):<copy from playbook: default density cap + which page type to prioritize + whether one beat may span multiple pages>
逐棒強調 ▸ 視覺 (棒3):<copy from playbook: which archetypes are preferred + what the visual should "reveal" + color leaning>
────────────────────────────────────────
(Note: `逐棒強調 ▸ 故事線 (棒1)` / `▸ 分頁 (棒2)` / `▸ 視覺 (棒3)` are field names the three-stage hooks match **verbatim** — write the ▸ and the single space exactly as above; don't turn them into indented sub-items or pad them with multiple spaces for alignment.)
```
> **The template-fill variant of the ▸ Brief**: template-fill does not run the three stages, so **do not** fill the three verbatim-matched fields `逐棒強調 ▸ 故事線 (棒1)` / `▸ 分頁 (棒2)` / `▸ 視覺 (棒3)` (no stage will read them). Keep the shared fields (`簡報用途` / `受眾與場合` / `工作子資料夾` / `必含素材` / `模式` / `套用品牌`), and **add** template-fill-specific fields (existing field names must **never** be changed; the new fields are merely additions):
> - `模板來源 (template-source)`:<user-supplied link | template name in TEMPLATE-INDEX + link>
> - `視覺處理 (visual-treatment)`:<recolor (external-template default) | keep | hybrid>
> - `欄位對映 (field-map)`:<template field → source content; mark "待補" for anything not extractable>
Create the working subfolder agreed at Step 2 and store the ▸ Brief in it (durable, same copy as the later ▸ Storyline / ▸ Pages / ▸ Visuals).
---
## Step 4-T — template-fill branch (replaces the three-stage relay)
When Step 1 determines it's **template-fill**: skip the three-stage relay and the storyline/page-split/visual gates, and run the precise template-fill flow below instead. What you assemble is the **▸ Brief (template-fill variant)** (see the note in Step 3, without the three per-stage emphasis fields).
**Before starting**: confirm the slide-pptx skill is installed (`~/.claude/skills/slide-pptx/`); if missing, ask the user to run `npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill slide-pptx` and **stop here**.
1. **Get the template**: user brought their own link → use it; otherwise `copy_drive_file` to copy the template selected at Step 2 (`TEMPLATE-INDEX`) into the working subfolder. **Always copy, never edit the master in place.**
2. **Export an editable copy**: `get_drive_file_download_url(export_format="slide-pptx")` to export the copy as .pptx — Slides' `get_page` has no text/position/color, so you can't precisely locate each shape (see memory `slides-heavy-edit-technique`).
3. **Read the field manifest**: take that template's field manifest (field → shape index / type / source hint) from the `TEMPLATE-INDEX` pointed to by `./references/template-source.md`. When the manifest has gaps, use `~/.claude/skills/slide-pptx/.venv/bin/python` + python-pptx to list shapes (index + type + existing text) and backfill one on the spot.
4. **Field extraction (field-extraction)**: extract the content corresponding to each template field from the source document (Doc / notes). **Mark anything not extractable as "待補" and hand it back to the user — do not fabricate.**
5. **map-to-template + fill**: use python-pptx to fill text, table cells, and dates by shape index. **Don't re-lay-out, don't move geometry.**
6. **Visual treatment**: per the ▸ Brief's "視覺處理 (visual-treatment)" (whose default value is read from the "visual-treatment default" column in `TEMPLATE-INDEX`; external / un-indexed templates default to `recolor`). `recolor` = map the template's original colors to Zynkr brand colors (the color values are loaded at runtime by `slide-visual-selector/references/brand-source.md`; **this layer does not hardcode hex**); `keep` = don't touch colors (when the template is already brand); `hybrid` = swap only key colors + fonts. Change fill and run fonts shape by shape.
7. **Back to Drive**: `create_drive_file(mime_type=slide-pptx, fileUrl=file://…)` to upload to the working subfolder. ⚠️ **workspace-mcp's `create_drive_file` with `fileUrl=file://` can only read from `~/.workspace-mcp/attachments/` (ALLOWED_FILE_DIRS)** — `cp` the local `.pptx` into that folder first, then upload via `file:///Users/<you>/.workspace-mcp/attachments/<name>` (text handoff packets via `content=` are unaffected). MCP cannot convert slide-pptx into native Slides — tell the user to do a one-click **File → Save as Google Slides** (see memory `gws-slides-api-disabled`).
8. **QA**: soffice → pdf → `pdftoppm -r 200` → Read PNG for a visual check; `markitdown` to check text. ⚠️ Don't name the temp script `inspect.py` (it shadows stdlib and breaks lxml import).
When done → hand off at the **Step 5 final gate**, then proceed to **Step 6 retro**. Re-version / partial edits follow Step 5's return-and-rerun approach (rerun steps 4–8).
---
## Step 4 — Run the relay (relay runner)
**Preflight before starting**: first confirm that the stages and the slide-pptx skill you're about to use are all installed (the three stages live in `skills/1-brand-marketing/`; slide-pptx is at `~/.claude/skills/slide-pptx/`). For whichever is missing, tell the user to run `npx skills add https://github.com/peter-tu-zynkr/zynkr-skill-builder --skill <name>` (slide-pptx must be installed separately), and **stop here** — don't barrel through and fail halfway.
**Transport**: when calling a stage via the **Skill tool**, paste the **full ▸ Brief block + the previous stage's handoff packet** verbatim into that call's args (including the ▸ Brief's "working subfolder" path), so the stage sees the ▸ Brief right there in context; **don't** drop a one-liner hint and expect it to go dig up the file itself. **Let each stage read its own SKILL.md and run its own logic** — I don't rewrite narrative/page-split/layout judgment here.
**Relay order (enter at the entry point determined in Step 1)**: skip the stages before whichever one you start from. ⚠️ If you continue from stage 2/stage 3, stage 1's storyline-finalization gate is no longer in this run's flow — in express mode there is then **no human checkpoint mid-stream**, leaving only the final .pptx gate; before starting, confirm with the user that the ▸ Storyline / ▸ Pages they pasted is already final.
1. **Stage 1 `slide-storyline-designer`**: pass the raw material + ▸ Brief. Stage 1 reads the ▸ Brief's "故事線 (棒1)" directives and the occasion, lays out the narrative arc, and runs the logic checks.
- **Storyline-finalization gate (kept in both modes)**: the storyline is the master template for every page that follows, so **the user must sign off whether in express or guided**. This is the first (and, aside from intake, the only) mid-stream human checkpoint in express mode.
2. **Stage 2 `slide-page-splitter`**: pass ▸ Storyline + ▸ Brief. Stage 2 reads the "分頁 (棒2)" directives and the page budget (as a target) and default density, and cuts pages.
- `express`: stage 2's human review is **non-blocking** (list the page split, note it can be halted at any time, auto-continue if there's no major issue).
- `guided`: keep stage 2's original per-page blocking HITL.
3. **Stage 3 `slide-visual-selector`**: pass ▸ Pages + ▸ Brief. Stage 3 reads the "視覺 (棒3)" directives, picks an archetype per page, writes the layout, and maps to pptxgenjs primitives.
- `express`: stage 3's human review is **non-blocking**.
- `guided`: keep stage 3's original per-page blocking HITL.
4. **Render** (who calls slide-pptx splits into two paths — don't render twice):
- **Normal path** (stage 3 ran this time): **stage 3 itself** calls the installed **slide-pptx skill** (Create from scratch, `Read ~/.claude/skills/slide-pptx/pptxgenjs.md`) once ▸ Visuals is finalized, renders page by page, and completes the QA slide-pptx requires (markitdown text check + subagent visual check). This layer only **confirms it ran**, and does not call again.
- **Continuing from ▸ Visuals** (Step 1 entry point = already has Visuals, stage 3 won't run): instead, **this layer (the orchestrator) directly** calls the slide-pptx skill to render + QA.
Both paths: colors/fonts per brand (when ▸ Brief "套用品牌" = yes), layout per ▸ Visuals' layout config.
> **Returning a stage / partial edits**: triggers include a gap in the story, a single page bursting past density, **must-include material exceeding the page budget**. Approach: use the Skill tool with the existing ▸ Brief + the previous stage's handoff packet + the specific edit request to re-call that stage and have it **re-emit the whole handoff packet**, then rerun the affected downstream stages (batch rerun, not per-page patching). Returning a stage doesn't require rerunning intake — the ▸ Brief is still in the working subfolder.
---
## Step 5 — Deliver + save (final gate)
1. **Final gate (kept in both modes)**: confirm slide-pptx QA was run by the responsible party (normal path = stage 3; continuation path = this layer) and isn't re-rendered; hand the finished `.pptx` (together with the visual-QA result) to the user to review, list a one-line summary per page, and ask them to confirm or flag the pages to change. To change → follow Step 4's "returning a stage / partial edits" approach: return to the corresponding stage to re-emit, then rerun the affected downstream stages.
2. After the whole run, the working subfolder holds the complete set of four: `▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals` + the finished `.pptx` (when continuing mid-stream, the earlier handoff packets are the versions the user provided).
- ⚠️ **When the working subfolder is on Google Drive**: the four packets are text — write them directly with `create_drive_file(content=…)`; but uploading the local `.pptx` (or any binary) needs `create_drive_file(fileUrl=file://…)`, and workspace-mcp can only read from `~/.workspace-mcp/attachments/` (ALLOWED_FILE_DIRS) — `cp` the finished file there first, then upload via `file://…/.workspace-mcp/attachments/<name>`.
3. Wrap up in one sentence: which purpose ran, how many pages, which mode was used, where the file is.
---
## Step 6 — Self-learning retro (net-new; HITL; silent by default)
After delivering and pushing the output to the working subfolder (**both branches run this step**: the three-stage relay and template-fill), spend a beat taking self-stock, and **only produce a proposal when there's genuinely something worth capturing**; a trivial one-off observation → **just stay silent, don't bother the user**.
**Retro checklist**:
1. **A reusable deliverable?** Is this output clean and worth filing into the SOT template library for future reuse?
2. **A new judgment rule / skill gap?** Did I hit a branch the SKILL.md doesn't cover, or make a judgment that should become a rule?
3. **A stable fact / pitfall?** Did I learn a stable environment fact, API limitation, or naming trap worth remembering?
4. None of the above → **trivia → silence.**
Only produce this when it's worth it (show it to the user, **write only on item-by-item approval**):
```
SLIDE_PACKET ▸ Retro Proposal
This run: <use-case / branch (relay | template-fill) / page count / file location>
Observations: <1–3 items, one sentence each>
Proposals (approve / reject item by item):
[1] Type: <template | skill-change | memory> — <one sentence> — Destination: <…>
[2] …
Rule: user approves item by item → only then write; no reply = no write. Trivia → silence.
```
**Routing after approval (item by item, executed only when the user nods; this step never edits the SKILL.md directly)**:
| Type | Destination | Action after approval |
|---|---|---|
| (a) Reusable deliverable | SOT template library + `TEMPLATE-INDEX` | `copy_drive_file` the deliverable → template-library folder; add a row to `TEMPLATE-INDEX`; produce and attach a field manifest |
| (b) New rule / skill change | `peter-tu-zynkr/zynkr-skill-idea` issue | `gh issue create`: **borrow only the issue-body skeleton from `skill-sourcer/agents/proposer.md` (Summary / What it does / Why)** and override — title uses `[Skill Change] zynkr-slide — <one sentence>`, label `skill-change` (**not** `skill-proposal`, to avoid being scaffolded as a new skill to a new path), Build Target Path points to the existing `1-brand-marketing/zynkr-slide`; **don't** fill the fields proposer.md depends on from extractor/classifier/deduplicator (a self-change has none of those inputs). ⚠️ proposer.md currently only has a "new skill" mode, so borrow only the skeleton, don't copy the whole package |
| (c) Stable fact / pitfall | Project memory directory (`~/.claude/projects/<project>/memory/`) | Write `<slug>.md` (frontmatter `type: reference` or `feedback`) + add a line to the index in `MEMORY.md` |
| trivia | — | Do nothing |
Skill changes **always** go through (b)'s issue pipeline; retro never directly edits this SKILL.md.
---
## Mode comparison (express vs guided)
| Checkpoint | express (default) | guided (with parameter) |
|---|---|---|
| intake (Step 2) | ✅ ask once | ✅ ask once |
| Stage 1 storyline finalization | ✅ blocking sign-off | ✅ blocking sign-off |
| Stage 2 page-split review | non-blocking (list + can halt, auto-continue) | ✅ per-page blocking |
| Stage 3 visual review | non-blocking (list + can halt, auto-continue) | ✅ per-page blocking |
| Final .pptx | ✅ review sign-off | ✅ review sign-off |
The spirit of express: **ask once up front, then only stop at two points — the master (storyline) and the deliverable (.pptx)**; the page-split and visuals in between run automatically per the ▸ Brief, and the user can halt at any time. guided suits high-risk decks or ones you want to control step by step.
---
## Outputs
A finished `.pptx`, plus the complete `SLIDE_PACKET` (▸ Brief / ▸ Storyline / ▸ Pages / ▸ Visuals) stored in the same working subfolder. The whole relay carries the ▸ Brief, so the same deck is aligned to "what kind of deck this is" from storyline through visuals.
## Limitations
`zynkr-slide` is a **thin orchestration layer**. What I **do**: intent detection, single-pass context convergence, ▸ Brief assembly and injection, driving the three stages and slide-pptx in order, and guarding the two human gates of express/guided. What I do **not** do:
- **I don't lay out the narrative arc or set the core thesis myself**: that's stage 1 `slide-storyline-designer` (1.25); I only feed it the purpose/occasion/directives.
- **I don't split pages or decide how much goes on each page myself**: that's stage 2 `slide-page-splitter` (1.26); the page budget is a target I give, but the actual page cutting is its judgment.
- **I don't pick the layout archetype or write the layout or pptxgenjs primitives myself**: that's stage 3 `slide-visual-selector` (1.27).
- **I don't render the `.pptx` myself or vendor the slide-pptx skill**: rendering and render-QA are handled by the installed slide-pptx skill; this skill only calls it.
- **I don't bundle brand content**: brand is always loaded at runtime per `./references/brand-source.md`; this public skill library holds no internal IP.
- **template-fill only fills, doesn't redesign**: the template-fill branch only **fills the fixed fields of an existing template + does visual treatment**, it doesn't re-lay-out or design a new narrative — to redesign, take the three-stage relay.
- **retro only proposes, doesn't auto-write-back**: Step 6 retro always **proposes first, writes only after the user approves item by item**, and **never directly edits this SKILL.md** (skill changes go through the `zynkr-skill-idea` issue pipeline).
+
+ ## House style
+
+ Writing style is **not owned by this file**. The house voice lives in two Google Docs under
+ `[@] 寫作指南` (`12DBdFz3SK22ie9im_ThFMI7IBRXsTZsV`), read at runtime:
+
+ - 《[2.0] Zynkr 通用風格指南 House Voice》 `10bOIQwRm9Pxwgct4hlwCwK_B4Pipai1HqBPZKzyRHSE` —
+ the universal core, plus the addendum for this surface
+ - 《[3.2] 禁用詞清單 Forbidden Words》 `1N5sHLP4qzmmhpCGsi6KElxi1z0MFe4QZ0Q_35T10Uyg`
+
+ Read both before producing client- or reader-facing text, and scan the draft against 《[3.2]》
+ before handing it over. If Drive is unreachable, say so in the output rather than proceeding
+ unchecked. Never re-implement either list inside this file.