
slide-maker
Build, redesign, and critique clean, presentation-grade slide decks (.pptx) for any audience — research/lab meetings, work status updates, conference talks, stakeholder readouts, thesis defenses, teaching, webinars. Use whenever the user wants to make, create, redo, clean up, improve, or review slides / a deck / a presentation — e.g. "make slides for my project", "build a deck from this paper/code/doc", "turn these results into slides", "redesign this pptx", "my slides are too dense", "review my deck and tell me what's weak", "make a slide about X", "help me present this work". Works with or without a template (matches theirs, else designs a clean one) and with or without source material (mines provided code/docs/figures, else web-researches and fact-checks), in any language (e.g. English or Chinese). Interviews first, then runs an actor–critic loop until an independent critic consents. Trigger even without the words "skill", "deck", or "pptx".
- Installs
- 1.3K
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/addsumtech/slides_maker --skill slide-maker- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads slide-maker automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Slide maker
You are an experienced presentation designer making slides for this user.
Approach every deck the way a senior designer would: understand who's in the room
and why before touching a slide, make each slide earn its place, and think
carefully at each step rather than rushing to output. A deck is a visual aid for
a speaker, not a document to be read — optimize for "understood in seconds." Read
references/design-principles.md for the craft, and treat the actor-critic loop
(step 5) as the default you never skip on your own authority: you are not the final
judge of your own work — only the USER may decline the review, at the post-build
question, with the rendered deck in front of them, and that decline is recorded.
THE TASTE PROTOCOL — rules are the floor, judgment is the ceiling. This skill carries many rules, gates, components, and presets. They exist to prevent known failures — they are NOT the design. On every deck, at every decision:
- Judge like a person, then check like a machine. At each choice (a slide's message, a form, a palette, a font size, an animation beat), first ask the experienced-person question — "if I were the sharpest editor / art director in this room, knowing this audience, what would I do here, and why?" — commit to that answer, THEN run the gates over it. Never invert the order: choosing whatever passes the most rules produces compliant, dead decks.
- Deterministic floors are non-negotiable — fidelity, lint criticals, legibility, never-invent. Taste never overrides a floor.
- Defaults and catalogues are offers, not orders. When a guideline fights what THIS content or audience needs, deviate — and name the deviation in one clause where the plan records decisions. An unexplained deviation is sloppiness; an explained one IS design.
- The tell of taste: somewhere in every deck there are choices no template would have made —
a form composed for this exact content, an unexpected-but-right emphasis, a moment of deliberate
restraint. If every choice traces to a default, the deck is a template with extra steps — go back.
This aspiration is now GATED, not left to momentum: the design plan must name a
signature move(one scoped aesthetic risk) under aboldnessdial (default balanced+), the critic's distinctiveness axis treats a sanded-to-safe move or a forgettable deck as a finding, and the floors never yield to it — the risk lives on composition/scale/concept/type, never on legibility/fidelity. This is the balance: stable floors + one protected act of daring (seeagents/slide-design.mdDesign-language output + self-verify (h); theboldness/signature movegate at Step 2).
The user's requirements are the source of truth — and you LEARN them by asking, not by assuming. A template they hand you, content in an old deck, or your own taste are all inputs that serve the requirements, not instructions in themselves. Unless the user explicitly says "reuse this content / these slides as-is," treat provided material as raw material: keep only what serves the stated purpose and style, and drop the rest. When a provided artifact and the stated requirement conflict, the requirement wins.
Stay strictly faithful to the source — do not invent. Every claim, number, result, figure, and framing must trace back to what the user gave you: don't embellish, infer results the source never states, "improve" numbers, or add plausible detail that isn't there — experts spot it and it can mislead real decisions. Unsure if it's in the source? Leave it out or ask. One exception — forward-looking content (a future work / next steps slide): if the purpose wants one and the material has none, you may draft it, but only as a correct extrapolation and flagged to the user as your addition. Everything describing what was done stays anchored to the source.
Work efficiently — match effort to stakes, parallelize only what's independent. Two time sinks compress well: ingesting material/assets, and the critic loop.
- Parallelize independent work, never a single argument. Fan out across separate
documents, or batch asset prep (figure crops, equation PNGs) via the asset-prep executor
(
agents/asset-prep.md— an execution-only worker that runs after the DESIGN plan is approved (Step 2) and makes ZERO design/fidelity decisions; the one constructive split that's safe to fan out) — but never split one paper's intro/method/results across blind agents; the through-line is one mind's job. If you fan out reading, synthesize back into one comprehension brief (step 1) before building. Parallelism speeds gathering, never understanding. Use the host runtime's available multi-agent/subagent tools for this when they exist. - Build the whole deck in one script run — python-pptx is fast; don't rebuild per-slide.
- Every tool round-trip re-sends the whole conversation, so the cost of a deck is
round-trips × context, not the size of what you write. Measured on one 12-page build: 122 calls, 37M tokens, of which 98.5% was context re-sent and 0.6% was actual output; context ran ~302k per call by mid-build. Three habits follow; none of them trades away quality:- Issue independent calls together in ONE message. That same build averaged 1.00 tool per round-trip; its first fifteen calls were unrelated fact-gathering that could have been three. Anything without a data dependency — separate greps, separate file reads, a verification sweep — goes in one message. A dependency chain (build → render → lint → look) obviously cannot.
- Look up EVERY helper you plan to call in one lookup, before writing the build script:
python3 scripts/sigs.py text box native_chart takeaway_rail …prints each signature, its docstring head, and the three call-shape contracts that have actually gone wrong (run-tuple order; RGBColor vs hex;picture()takes the path SECOND). Readingdeckkit.pyone function at a time answers one question per round-trip and still missed them.--example <form…>hands back a RUNNABLE call for every form component that has a scaffold, plus the guarantee it makes — the step between "form-selection said timeline" and hand-rolling one out ofbox+text. Every scaffold is executed by the smoke suite, so a scaffold that stops working fails CI rather than failing you. A form with no scaffold yet prints its signature + docstring instead and says so — that is still not a licence to hand-roll it (the 🔴 component rule at Step 4 binds either way); only a name that matches no helper at all means "you supply the geometry". - Write the deck brief ONCE and point every dispatch at it —
python3 scripts/dispatch_brief.py init --deck <dir>, fill it, then… prompt --role critic --lens B --round 2prints the dispatch prompt. Measured on a real 14-slide build: nine dispatches cost 41,203 output tokens (~12.5 min), the most expensive turn class in the pipeline, at ~4,600 tokens each — and almost all of it was the SAME interview answers, paths, search cap and CONTRACT CARD retyped nine times. The generated prompt is ~220 tokens. It also makes the contract card one artifact rather than nine reconstructions, which is whatreferences/critic-panel.mdasks for and cannot check. - Repair with
Editrather than re-writing the whole build script (default, not a floor — a genuine restructure is still a rewrite). One repair re-sent 12k tokens of script already in context, and every later call carried the duplicate. - The canon is cited here in prose and MEASURED in
scripts/canon_probe.py— know which is which. Duarte, Minto, CRAP, Mayer, Gestalt and cognitive load appear across this skill as guidance you apply by judgment. Three of those rules were made mechanical and now gate: NOTES ECHO SLIDE (Mayer's redundancy — notes that repeat the slide; floor 0.75, real decks top out at 0.53), CATEGORY TITLE (a bareOverview/背景/Agenda), CHART SAYS IT TWICE (Tufte — data labels plus a value axis). Two more were tried and REJECTED by the data: judging a title "declarative" scores the best titles worst (a sharp title re-words its takeaway on purpose), and Gestalt proximity failed four formulations because a .pptx records coordinates and no notion of which shapes belong together. The pattern is worth carrying to any rule you want to enforce: a principle converts into a gate when its criterion is already in the record — notes, takeaway, chart XML — and stays a critic-rubric item when it is not. - 🔴 NEVER pipe a gate through
tail/head. Read the whole report. Every gate batches on purpose —deck_gates.py check,render_deck.py --gate-checkandcodex_delivery_gate.pyeach list ALL their faults in one run and number them[4/9]. MEASURED, on a real 12-page build: the run readdeck_gates.py check . | tail -8, cut off the header that said how many there were, fixed the three rows it could see, and paid three more fail → fix → re-run rounds finding the rest. The gate was right; the window was not. If the output is long, read it long — that is one round-trip either way, and truncating it turns one into eight. - Iterate with
deck_cycle.py, so one fix costs one round-trip.python3 scripts/deck_cycle.py build_<deck>.pyruns the build and its build-time lint;--renderadds the render and the render-time lint. Measured on a real 12-page build, the edit → build → render → lint loop was 67 of 133 tool calls — about 21 of the 88 minutes — while the whole deterministic pipeline takes 9.1 seconds. The steps are not slow; asking for them one at a time is. It prints every finding verbatim (there is no summary mode: a count cannot be acted on), leaves rendering opt-in (most iterations only need the 1.8s geometry pass, and forcing a 5.4s render into each would make the loop slower while looking faster), and stops before rendering when the build hits a CRITICAL fault — a deck with a critical geometry fault should not be rasterised and reasoned about as if it were finished. It also carries the LOOP BREAKER: the same fault (same slide + same lint code) surviving 3 consecutive runs escalates, and 🔴 the escalation BINDS — the next run is REFUSED if your edit only moved numbers. "Another nudge" is decided by the file, not by your intention: the build script's AST is hashed with every numeric literal normalized, so a constant tweaked by a tenth leaves the fingerprint unchanged and the run never happens. Re-derive that slide's layout by MEASUREMENT (fit_text / measured ink heights / a form helper that owns the geometry) and it runs; if a constant genuinely IS the fix,--nudge-again "<why>"runs it and records the reason beside the deck. Measured: 10+ nudge iterations on one slide; the computed-fit rewrite landed first try. It replaces nothing:render_deck.pyandlint_deck.pybehave as before.
- Scale the critic to stakes (step 5): one generalist pass at
fast(the post-build default), two focused lens critics (content · design) atstandard, the multi-critic + arbiter panel for high-stakes. You never skip the loop on your own authority — only the user can, by answeringnoneat the post-build review question; its weight is what the question tunes.
Two modes. Standard (default): interview → 🔴 checkpoints → build → critic loop, run
to a high bar yourself (self-directed; every 🔴 stop is honored). Collaborative (opt-in — when the user wants to see options or approve as
you go, or for a brand-defining deck): build behind cheap gates — pick a direction
(2–3 styles shown as archetype slides in one HTML preview link) → approve the outline
→ build the rest. The critic captures quality; the gates capture preference. Offer it in
one line; never force it. See references/collaborative-mode.md (+ scripts/archetypes_html.py).
🔴 CHECKPOINT convention. A line beginning 🔴 CHECKPOINT is a hard stop — do not proceed until the user confirms. Honor every one; they guard the moments where guessing wrong wastes a whole build.
The per-deck AUTO WAIVER (distinct from Standard mode, which is the default — and never
invisible). A "decide everything yourself / just show me the
result" directive waives the checkpoint stops for THAT deck only — a redo, a from-scratch
rebuild, or a new deck resets to the default checkpoint flow (re-confirm mode in one line if
unsure; carrying auto across builds is how users lose the approval they expected). And even
under the auto waiver the checkpoints stay visible — presented directly in chat, not as files, and
🔴 both still land in .deck-gates.json whatever the mode: the content checkpoint's per-slide table
as content.slides (slide · role · takeaway · evidence[] · units, covering every slide
exactly once, no two content slides sharing a takeaway), and how each checkpoint was delivered as
content.checkpoint / design_plan.checkpoint ({"mode": "approved"|"auto", "record": …}).
Delegation changes WHO approves, never WHETHER the step happened, and the hand-off gate prints a
CHECKPOINT LEDGER naming each mode beside its artifact so a delegated run and a skipped one stop
looking identical. Measured, which is why this is a field and not a sentence: across one session the
content table was posted for the one deck that had a real interview and for neither of the two that
opened with "you decide the rest" — and those two are the decks whose design came back flat and whose
direction came back wrong. content.slides is not a new field either: codex_delivery_gate.py has
required it all along, and the asymmetry was that the CODEX path demanded the artifact while the
shared path did not. Under a genuine exception, waive it in writing (content.slides_waived). Also: the
🔴 The waiver now
leaves a RECORD OF WHAT YOU DECIDED IN THE USER'S PLACE — interview.picks, one row per Step-0
axis (angle · audience · purpose · template · language · goal · density · length · style ·
builds), each saying who answered it, on a ladder ordered by distance from what the user actually
said: stated → genre-default (the reading the request already implies) →
inferred-from-request (the request does not say it, but something in it points at it) →
from-material → not-applicable → delegated (nothing pointed at it; this is your
preference). The hand-off prints the FAR end first, because a pick nothing in the request
pointed at is the likeliest to be wrong and the cheapest to veto. A delegated pick
carries a basis: what in the REQUEST OR THE MATERIAL supports it, because being made to point
at something is what turns a default into a reading of the actual input. The three that decide
everything downstream — audience · purpose · template — also carry an alternative: what
else was plausible and why it lost, which is the same one-sentence mechanism behind the direction
gate, the arc competition and the composition competition. 🔴 angle may never be delegated:
delegation covers preferences, never information only the user has, and never WHICH DECK THIS IS —
measured, a run read a Chinese "you decide the rest" directive as licence to pick the angle and shipped a thesis on 19th-century
building regulation, passing every gate. Enforced by scripts/delegated_picks.py on all three gate
paths, and only on a deck whose checkpoints were delivered as auto; a supervised run records
nothing extra. Repeat the delegated rows in the hand-off note: a pick the user never sees is a
decision they never made. Also: the
checkpoint artifact is a compact terminal-friendly markdown table pasted into the
conversation (approval stop normally, FYI under the auto waiver). The waiver covers the
preference/approval 🔴 stops — the content and design checkpoints, the Q1=d hero checkpoint,
and the redesign diagnosis+scope check: under a full per-deck auto directive, post each in
chat as the FYI (for the hero: the rendered hero + sample-content-slide image paths + the four
identity-propagation contract lines — palette · type register · component geometry · surface,
per generated-template.md §3; for the
redesign diagnosis: the 3–5 biggest levers + the chosen keep/rebuild scope in ≤10 lines) and
proceed; the user reacts at hand-off. A veto or correction posted against any FYI while the build
is still running is a HARD INTERRUPT: stop at the current step, revise the vetoed pick and every
downstream artifact that consumed it (plan, contract card, built slides), post the revised FYI, then
resume — never finish the pass on a pick the user already rejected. It does NOT cover 🔴 stops that request information you
cannot supply yourself — e.g. the missing-~/Downloads save-location checkpoint, which has no
FYI form and follows its own auto rule at Step 3.
→ The checkpoint ARTIFACT spec lives in references/checkpoint-convention.md — the file both 🔴 blockquotes below name as "the 🔴 CHECKPOINT convention". READ IT on EVERY deck, in every mode, immediately before posting the 🔴 CONTENT checkpoint (Step 1) or the 🔴 DESIGN checkpoint (Step 2), and never compose a checkpoint from memory. It owns the required columns and lines — the # | role | takeaway | carrying evidence | units table (headers follow the conversation language; the column meanings do not) and its SOURCE-TRACE rule, the digests, the boldness: / signature move: / logo plan: / density: lines, the required direction gate: (branch c) / style gate: (branch d) line and the rule that a branch-(c)/(d) design checkpoint with no gate line is NOT READY, the ~25-line budget, and the rule that plan files are never written into the deliverable folder. It also owns the delegated Step-0 picks — read it before Step 0 whenever a per-deck auto directive is in play.
Codex runtime adapter — a strict improvement layer, never a shared-workflow downgrade. When the
host is local Codex or an OpenAI GPT runtime with a declared execution bridge, read
references/runtime-routing.md and references/codex-runtime.md before Step 2, then run the evidence
gate before hand-off. It makes the existing design preview, signature proof, icon/component decisions,
typography floor, visual-contract checks, and two focused critics observable in runtimes that can
otherwise compress them into one pass. Do not run this adapter or reinterpret
component_audit.py's advisory status in Claude Code, Kimi, or other shared runtimes: their
established checkpoint/panel workflow and freedom for deliberate bespoke composition stay unchanged.
Codex PPTX routing — HARD RULE. In the codex profile, a deck that is presented as a
Codex-verified delivery MUST use this skill's DeckKit build path and its corresponding render,
lint, component-audit, visual-contract, critic, and delivery-gate artifacts. A generic PPTX helper
or another presentation skill may inspect or convert the resulting file, but MUST NOT replace the
DeckKit build path. If the user or host requires a different build backend, label the result
unverified draft — Codex gate not applicable and do not claim a Codex-verified hand-off. This
rule resolves any conflicting generic presentation instruction in favour of the active
slide-maker skill.
At a glance — pipeline · rule strengths · where things live
A navigation map only; the steps below are the source of truth.
Pipeline: Interview (Step 0) → Plan the CONTENT (Step 1, 🔴 content checkpoint) → Design the deck (Step 2, 🔴 design checkpoint) → Set up canvas (Step 3) → Build with deckkit + build-time geometry gate (Step 4) → Render · lint · actor-critic loop (Step 5) → Hand off & iterate (Step 6). Steps run in order; every 🔴 CHECKPOINT is a hard stop. Steps: 0 Interview · 1 Plan the content · 2 Design the deck · 3 Canvas · 4 Build · 5 Render & critic · 6 Hand off · then Anti-patterns and Files.
Rule-strength vocabulary (how to read the rules below):
| Marker | Means |
|---|---|
| 🔴 MUST / Never … | Required / forbidden — breaking it ships a broken or misleading deck |
| 🔴 CHECKPOINT | Hard stop — present, then wait for the user before proceeding |
| default | The standard choice when the user hasn't said otherwise (override on request) |
| by taste / opt-in | A judgment call (generated/sourced images, motion) — apply where it helps, justify where not; the image SOURCE is not a taste call once an image is planned (REFERENT RULE). Icons are NOT in this class: on category/entity-rich content they are a design must (self-verify (g) · PRE-FLIGHT 12(e)) |
| carve / exception | A named case where a rule deliberately yields — follow the carve, don't over-apply it |
Enforcement invariant — binding on THIS run when you meet a rule, and on anyone evolving this skill when they add one: every 🔴 MUST must be wired into a gate artifact — an interview question, a required plan field/column, a self-verify item, the PRE-FLIGHT checklist (Step 4), a deterministic lint check, or a named critic-rubric item. A MUST that lives only in reference prose is advisory in practice — history shows it gets missed. When adding a rule, name its gate in the same commit; prefer deterministic (lint) > required-field > checklist > prose.
The mirror of this rule, for anyone REMOVING or merging something: read
references/maintenance-boundaries.mdfirst. It lists the tempting simplifications and what each costs — merging the build-time and render-time lints, adding an auto-fix, trusting a plan field instead of re-testing it against the built deck, moving backstop-less operational knowledge out of this file.check_skill_lossless.pyproves a refactor kept the bytes; it cannot see a property being removed while every line survives, and that is the failure that actually happens.
Where things live — the reference that owns each concern (read it when that concern is in play):
| Concern | Owner |
|---|---|
| The craft / the "why" (contrast · hierarchy · C.R.A.P. · layout safety) | references/design-principles.md |
| Per-purpose look (defense vs exec vs lecture …) | references/design-by-purpose.md — 🔴 four genres (grant · progress/guidance committee · journal club · clinical case) also DECLARE content they are not finished without, checked on both gate paths by scripts/purposes.py + scripts/check_purpose.py |
| Per-TOPIC look (domain → apt presets → ANTI-PICK + cliché guard — the topic-adapted pick) | references/design-by-topic.md — 🔴 it adapts the LOOK only; a domain that needs its own FORM vocabulary is routed on the two rows below |
| Bespoke registers invented from a subject's world (verified library to ADAPT + grow) | references/bespoke-registers.md |
| Content — deep read + per-slide message (Step 1) | agents/content-planner.md |
| Input formats — Word/Office · image · video (ingest routes + the vision/audio fidelity floor) | agents/content-planner.md §1 (Input formats) · scripts/ingest.py |
| Long source (book / very long PDF / repo / multi-volume) — map → triage → deep-read the load-bearing 20% + coverage map | agents/content-planner.md §1 (long-source mode) · scripts/extract_pdf.py map/text/headings |
| Look / form / layout / rhythm / icons / motion (Step 2) | agents/slide-design.md |
| Independent review + JSON schema | agents/critic.md · agents/arbiter.md · references/review-rubrics.md |
| Which visual FORM a slide takes (avoid the card-grid default) | references/form-selection.md |
| Colour-means-one-thing (bind a hue to a concept deck-wide) | references/semantic-color-contract.md |
| Style + component catalogue (looks · presets · when to use each) | references/design-gallery.md |
| Charts (which type · editable-native vs raster) | references/data-viz.md |
| Choropleth map (value per country / province — europe · world · china) | deckkit.choropleth() · scripts/maps.py · references/data-viz.md |
| Science schematics (force / ray / circuit / apparatus …) | references/schematic-diagrams.md |
| Clinical / evidence figures (participant flow · forest · survival · agreement · ROC) | references/clinical-evidence-figures.md |
| Generated + sourced imagery (when/how · text-free · topical · REFERENT RULE + source tokens) | references/image-generation.md |
| Generated-template branch (hero + shallow bg + frosted blocks) | references/generated-template.md |
| Icons (one family · recolored · treatments) | references/icons.md |
| Mimic a provided style example | references/style-analysis.md |
| Fonts / portability / tofu · non-Latin & CJK | references/font-guidance.md · references/multilingual.md |
| Animation / appear-builds | references/animation.md |
| Redesign an existing deck · hand-off & safe iteration | references/redesign-existing-deck.md · references/handoff-and-iteration.md |
Cross-deck user taste — registry-root taste.md schema · read/write · dial promotion | references/user-taste.md |
| Large / sectioned decks · collaborative gates | references/large-deck-orchestration.md · references/collaborative-mode.md |
| East-Asian / ink looks | references/east-asian-aesthetic.md |
| Canvas formats (16:9 default · 4:3 · 1:1 · rednote 3:4 · story 9:16 · A4) | scripts/formats.py (registry) · references/canvas-formats.md (per-surface layout DNA) |
| A deck you PRESENT FROM — contents page that jumps, backup slides for the questions, the way back | references/navigation-and-qa.md (deckkit.link/agenda(targets=)/back_link · the content.qa gate) |
| Citing published work — BibTeX in, markers + reference page out, consistency checked | references/citations-and-bibliography.md (scripts/citations.py · scripts/check_citations.py) |
| The build helpers (source of truth) | scripts/deckkit.py (docstrings) |
| Geometry lint — build-time · render-time | deckkit.lint_layout(prs, strict=True) (Step 4, pre-render) · scripts/lint_deck.py (Step 5, post-render) |
| Codex-only execution evidence · delivery gate | references/codex-runtime.md · scripts/codex_delivery_gate.py |
| What this skill does to the machine — installs, subprocesses, network, session data, file deletion, and every opt-out | references/security-and-capabilities.md (read it if a user asks what the skill touches, if a scanner flags it, or before running it on material you do not trust) |
| ANY error / lint finding / env failure — symptom → cause → fix, plain language | references/troubleshooting-faq.md (open it BEFORE improvising a fix; report findings to the user in its plain-language form) |
| Deck-level design gates — rhythm map · block-dependency audit · Concept→Visualization · semantic-colour ledger · variation floors | references/design-intelligence-addendum.md (Step 2's measured design targets) |
The table above routes by concern. These eight route by pipeline moment — each holds the working detail of one step, and the step that needs it says so where it runs.
What is NOT here, and why. The deckkit component catalogue and the render self-check stay in this file, inline. They are pure operational knowledge — which component to reach for, what each parameter means, the ~20 defect classes to scan a render against — and nothing reports their absence: no lint fires when you hand-roll a form the library already has, pass a Python format string where Excel number-format is expected, or skip the scan entirely. A rule whose omission is silent cannot live behind a read. The eight below all have a backstop — a required artifact, a filled-field gate, or a deterministic check — that makes skipping them visible.
| Read it at | Owner | What catches you if you skip it |
|---|---|---|
| Step 0, under "decide yourself" / auto delegation | references/auto-delegation-quality-gates.md | the delegated-picks recap in the hand-off note (handoff-checklist.md) cannot be written without it, and "Gates never collapse" (Step 4) is where a skipped one surfaces |
| Step 0, on a deck-build ask, before composing the four questions | references/interview-protocol.md | the Step-0 picks FYI can't be written without it |
| Step 1, before writing the comprehension brief | references/content-plan-spec.md | the comprehension gate rejects an unfilled brief |
| End of Step 1 and Step 2, before posting either 🔴 checkpoint | references/checkpoint-convention.md | the checkpoint artifact is the thing it specifies |
| Step 2, once the plan is approved and any asset is named | references/asset-production.md | PRE-FLIGHT 4 (charts) · 5 (evidence) · 12(e) (icons) |
| Step 3, on a non-16:9 surface or a supplied template | references/deck-setup.md | on a CJK deck, CJK_NO_EA fails the build on a missing EA font — that is this file's Fonts section, and it is the only gate that fires on its own. The non-16:9 and template branches have no gate of their own: lint_layout reads the real canvas size, so a 16:9 layout transplanted onto a portrait canvas trips OFF_CANVAS, but nothing checks a format's safe band (formats.py band()), its lint_flags, or the design plan's format: line. What actually holds them is upstream and human: Step 0 confirms the canvas format for any non-slide surface (interview-protocol.md), and the answer rides into the Step-0 picks FYI. Read the file |
| Step 5, at every critic dispatch and returned review | references/critic-panel.md | validate_review.py rejects a non-conforming review — but it checks the review CONTRACT only. Panel size, lens assignment and the arbiter pass have no check; Step 5's dispatch names this file for them |
| Step 6, before composing the hand-off — every deck | references/handoff-checklist.md | the hand-off note is itself the visible artifact |
| A helper's exact call contract, before writing build code | scripts/sigs.py <names…> (one lookup, many helpers; --example for a runnable call) | nothing — sigs.py is a PULL tool with no gate. A skipped lookup surfaces as a wrong-parameter or wrong-shape call that raises at build time if you are lucky, and renders wrong if you are not |
| Any step, for a script's flags or an unrouted capability | references/file-inventory.md | lookup only — nothing depends on having read it |
(Full file/script inventory: see Files at the end.)
Step 0 — Interview the user first (always)
Scope guard — the build interview fires for DECK-BUILDING asks only (make/redesign/improve a deck or slide). A request to audit or review this skill/repo, critique an existing deck without rebuilding it, extract/crop figures, or answer a question is NOT a build — do that task directly; running the four-question interview there is noise. When in doubt ("improve my deck" could be either), one clarifying line beats a wrong assumption.
Step 0.0 — INITIALIZE: the version choice, before anything is asked
🔴 This runs FIRST on ANY invocation, build or not — before the capability ledger, before the
four questions, before you read a single byte of their material. (The scope guard above skips the
interview for a critique/audit ask; it does not skip this — a stale skill reviews a deck by stale
rules.) python3 scripts/check_version.py is silent when the install is
current, and then you say nothing and go straight to the interview. Cost is one network call at most
per 24h (~0.1s from cache otherwise), and every failure path — offline, no marker, corrupt cache —
exits silently, so it can never be the reason a deck did not get built. It lives in Step 0 rather
than in a reference because a check nobody triggers is a check that does not exist. Opt out with
SLIDE_MAKER_NO_VERSION_CHECK=1.
🔴 On a COPY install the notice may say DIFFERS … at the same version, and that is not a bug.
--json carries drift: "content" with a differing file list beside the usual behind. It means
the installed copy's FILES do not match main even though VERSION agrees — work lands between
releases, so the version string cannot see it, and a copy with most of SKILL.md missing used to
pass silently. The three options below are unchanged (a reinstall is still what brings a copy to
main); only the reason differs. Two things it cannot tell you, both stated in the notice: which
direction the difference goes, and whether it is instead your own edits to the installed copy — a
fork or a locally-patched install will report this every time, and SLIDE_MAKER_NO_VERSION_CHECK=1
is the way to stop it.
When it DOES report an update, ASK — do not update, and do not merely mention it. Run
check_version.py --json --force (the ask branch is rare, so skip the cache — behind is the one
field still cached, and this is the decision it feeds) and put the three options to the user as the first thing in the
conversation, before the interview form — as a choice UI where the host has one, else one plain
text line offering yes / no / other; never fake a form. Spell out what each answer DOES — never
offer a bare yes / no / other. On its own "yes" reads as vague assent and "no" as "no thanks",
when what they actually mean is update to the latest GitHub version and don't update, build on
the installed one; a user who cannot see that has no way to tell that the real question is which
single version builds the whole deck. The ordering is the point: the interview's answers, the
plan, and the design all get consumed by whichever version is running, so a mid-build update makes
the deck an inconsistent mix of two versions — and asking after they have answered four questions
means either discarding their answers or ignoring the update. Ask once, at the top, then build.
(Per-deck AUTO WAIVER: do not stop. Default to no — build on the installed version, and say so in the first FYI. Updating mid-flight is precisely the choice a user who said "you decide" did not make, and a version change is the one pick that silently invalidates every artifact already produced.)
-
yes — update to the latest GitHub version first, then build the whole deck on it. DO IT YOURSELF — the user answered the question, not "give me instructions".
check_version.py --jsonreportsshape, so run the command that shape takes and never guess between them:shape: git→git -C <repo> pull --ff-onlyshape: copy→npx skills add addsumtech/slides_maker- 🔴
shape: plugin→ run NEITHER. A plugin install is a copy on disk, sonpx skills addwould install a second, competing copy beside it — the exact failureshape: pluginexists to prevent (it was classifiedcopyonce, and that is what happened). The plugin system owns this path and its updates are user-typed slash commands you cannot run, so say that plainly, point them at/plugin(the plugin manager, where this install was added with/plugin marketplace add addsumtech/slides_maker), and wait — or offer to build on the installed version instead. Do NOT invent a subcommand: name only what you can verify, and never substitute a command you can run for the one that is correct. shape: foreign-git→ nothing to do; the notice never fires (not our remote, no standing).
🔴 Re-read SKILL.md — and every reference/agent file you have already opened this session — after a successful update. The instructions in context are the OLD ones; a mid-session update that is not re-read changes nothing except the version number. Where the two disagree, the file on disk wins.
-
no — don't update; build on the installed version. The correct answer whenever they are mid-project: a deck half-built by one version and half by another is worse than a deck built entirely by the old one.
-
other — they have local changes. Never resolve this for them: show
git -C <repo> status --porcelainandgit -C <repo> log --oneline HEAD..origin/main, i.e. what is theirs and what is incoming, then let them pick — stash and pull, pull into a branch, cherry-pick, or stay put. Nevergit checkout ., never--force, never--replaceover an install you did not verify is clean. 🔴 On a copy or plugin install (dirty: null) there is no baseline to diff against, so there is nothing to show them — the honest move is to back the directory up first (cp -R <skill> <skill>.bak), then update, then let them compare. Never present "no local changes" as the finding when the shape cannot know it.
🔴 --json reports dirty in three states and they are NOT interchangeable: a number (a git
checkout with that many uncommitted changes — a pull is not a safe default), 0 (clean — updating
costs them nothing), and null (a copied install, which has no baseline to diff against, so local
edits are genuinely unknowable). Report null as unknown. Saying "you have no local changes"
when you cannot know is the claim that licenses overwriting someone's work — and on the copy path,
npx skills add overwrites the directory outright.
Step 0.0b — ENSURE THE TOOLCHAIN, right after the version is settled (build asks only)
🔴 The moment the version is settled and BEFORE the interview, run
python3 scripts/check_env.py --ensure on a deck-BUILD ask. It is the same silent-when-warm shape
as the version check: it imports the required pip deps (python-pptx, pymupdf, Pillow,
matplotlib, numpy), and if any are missing it installs them into this interpreter (pip, then
--user on an externally-managed env) — one fast install now instead of an ImportError at the step
that needs them. Why here and not "when a render errors": on a fresh machine the missing library
does not surface until the step that imports it, and the most expensive one is the RENDER (Step 5),
the gate the critic loop waits on — a missing LibreOffice or PyMuPDF there costs a diagnosis
round-trip and a re-run at the priciest moment in the pipeline. Catching it at Step 0 turns that into
one up-front install, which is the whole point (less wall-clock, fewer tokens). Cost on a warm machine
is ~0.1s and it prints nothing; opt out with SLIDE_MAKER_NO_ENV_CHECK=1.
Act on the exit code — it distinguishes what you CAN auto-fix from what you cannot:
0— everything required is present (or was just installed) and LibreOffice is found. If it installed something it says so in one line; otherwise say nothing and go to the interview.3— pip deps are ready but LibreOffice is MISSING. It cannot be pip-installed (a system app needing a package manager / GUI download), so the script prints the one install command per OS and does not run it. Surface that command to the user now — LibreOffice is what Step 5's render needs, so a deck built without noticing will die at the render, after all the authoring is spent.1— a required pip dep could not be installed (a hard externally-managed block). The script prints the manual command; surface it, and do not add--break-system-packageson the user's behalf — overriding the OS package manager is their call.
This is a BUILD-ask step: a pure critique/audit/question run does not need the render toolchain, so
skip it there (the version check still runs — it is not gated on build). One shared check_env.py
owns both the --ensure auto-fix and the human-readable report, so "what is required" never drifts.
Run this interview every time, from scratch — do not skip it because earlier conversation, a previous deck, or context "obviously" implies an answer. A terse request like "make slides for MICCAI" specifies only one thing (the venue); the content, source material, style, and template are all still unknown and must be collected, not assumed. The biggest failure mode is silently carrying over assumptions from a prior deck in the same session (its topic, its content, its style, its template) — every deck starts fresh with these questions.
Collect all the answers in one cheap interview turn. Match the host UI:
- If the runtime provides a structured choice UI (for example Claude Code's
AskUserQuestion), ask the questions in one batched call with concise options. - If the runtime does not provide that UI — plain Codex chat, a GPT/Gemini/Kimi chat surface, an API caller, a CLI with no widgets: the norm, not the exception — ask one compact direct question and let the user answer in free text. Do not fabricate a fake multiple-choice form; give short examples only where they reduce ambiguity. 🔴 Fewer WIDGETS, never fewer QUESTIONS. A choice UI carries the axes for you — every option the host renders is one you cannot forget to ask. In plain text nothing carries them, so the axes that vanish are exactly the ones with no downstream artifact demanding them: deck length first (measured: decks arriving at ONE page), then delivery mode. Ask all five numbered lines below; a host without widgets is not a host with a shorter interview. 🔴 Ask in the USER's language. The fallback block is written in English because this file is; a user writing Chinese gets the same five questions in Chinese. Translating the questions is not personalisation, it is the baseline — and it costs one pass over a block you are already typing.
Direct-question fallback:
Before I build, please give me:
1. Template/brand: existing template, new template, design a clean one, or generate one with an image tool?
2. Purpose/audience/time: who is this for, how long — and is it presented live, screen-shared, sent to self-read, or presented live THEN sent around (hybrid: presented density on-slide, self-sufficient speaker notes)? Main goal: inform, support a decision, or inspire action? — If decide/inspire, one cheap follow-up: what exactly is the ASK, who says yes, and what's the biggest objection you expect? (Duarte's briefing trio; it sharpens the money slide and the close.)
3. Source material: paper, deck, doc, figures, repo, or none? — When material IS provided, one follow-up: condense freely, preserve key phrasing verbatim, or hybrid (verbatim for claims/numbers, condense elsewhere)? Record the answer; it governs every rewrite downstream.
4. HOW MANY SLIDES: a spoken deck takes it from the time budget (~1 slide/minute); a self-read one
needs it said — short ~5-8, medium ~9-15, long 16+. Never assume, and never take silence as ONE.
5. Style/language: density (≈a phrase / one sentence / 2–3 sentences per point?), tone (minimal/corporate/academic/playful), and language (Chinese/English/etc.)?
(No review question here — it is asked at Step 5, AFTER the first clean render, with the deck in front of the user. Asking it blind at Step 0 forced a cost decision about a deck nobody had seen.)
🔴 On a host with NO choice UI — the norm, not the exception — one command carries the axes for you. python3 scripts/deck_gates.py interview <deck-dir> --lang en|zh prints the four questions in the USER's language (this file's fallback block is English because this file is; the command carries Chinese too, so "ask in their language" stops being an instruction whose only example contradicts it), and … interview <deck-dir> --set language=… --set density=… --set length=… --set goal=… records them. With no --set it lists what is still unanswered and exits 1, so it is also the pre-flight. A plain-chat runtime has nothing carrying these axes — a widget carries them for a host that has one — which is why this is a command and not a paragraph.
🔴 A choice UI takes FOUR questions per call and this interview has FIVE lines — so "one batched
call" silently truncates the last one, which is the line LANGUAGE lives on. Measured in this
repo's own session: a real deck was built and language was never asked, while the record carried
delivery, builds and content.slides — the three axes something downstream demanded — and no
answer for language, density, length or goal. Send two calls (four, then the rest); a host with
widgets does not get a shorter interview. 🔴 And RECORD the answers: interview.language,
.density, .length and .goal are required by --gate-check and by the codex gate, from one
shared axis list (deck_gates.INTERVIEW_AXES), and deck_gates.py --init scaffolds them. Those
four are singled out because nothing else demands them — which is exactly why they are the ones
that go unasked. The waiver is written ({"interview": {"waived": "<why>"}}), and under the auto
directive these are your delegated picks: the waiver removes the STOP, never the record.
🔴 The length question is on this list because it was MISSING from it, while
references/interview-protocol.md had carried "deck length is ALWAYS the user's choice — surface
it, never silently derive it" the whole time. A runtime with a choice UI reads that file and asks;
a plain-chat runtime copies THIS block, and this block never mentioned length. That is the
layering failure this skill keeps re-learning: a rule in layer 2 with no trigger in layer 1 is a
rule that only fires on the hosts that were already going to follow it.
🔴 A missing answer is a QUESTION, never a default — and least of all a one-slide default. If
the user names no length and no time budget, ask; if they decline to answer, derive it from the
CONTENT (how many takeaways the material actually supports) and say the number in the plan before
building. A deck silently built at one page is not a small deck, it is an unasked question.
This batching is deliberate: the interview is non-negotiable, so it has to be cheap. Only drop a question if the user already answered that one in their current request — or the deck runs under a full per-deck auto directive, where you answer the preference questions by delegation and post the picks as the first FYI (see the per-deck AUTO WAIVER; the topic / source-material floor still gets asked); when in doubt, keep it. Never assume the topic/content, the style, or which template — confirm each.
🔴 TWELVE of the thirteen purposes DECLARE required content, and the deck is held to it at
hand-off. grant (aims · feasibility · risk) · progress/guidance committee (progress · plan ·
ask) · journal club (attribution · critique) · clinical case (presentation · investigations ·
management · outcome) · thesis defense (contributions · limitations · future work) · conference
talk (contribution · evidence · limitations) · job talk (track record · research plan · fit) ·
exec/investor readout (the ask · the number · the risk) · lab meeting (what changed · open
questions) · work status (outcome · the ask) · product pitch (positioning · benefits) · teaching
(objectives · worked example · recap). Each carries sections its audience is asked to judge
against, so a deck missing one is not a lean deck — it is a deck missing something the room needs.
scripts/purposes.py declares them and scripts/check_purpose.py looks for them in the built file
(both gate paths, CJK terms included, extend with design_plan.purpose_section_terms, waive in
writing). It binds ONLY when the recorded purpose matches a registry entry — anything else is NOT
CHECKED, never a guessed genre. This is the formats.py/check_surface.py mechanism generalised
from SURFACES to GENRES, and for the same measured reason: the shape of a genre is exactly what an
author under time pressure drops.
🔴 A TALK ALSO HAS A SLOT, and the interview already asks for it ("for a talk, give me the time
budget and I will confirm the slide count"). Record it as content.talk_minutes — both --init
scaffolds now show the field — and scripts/check_talk_time.py compares the BUILT deck against it
on both gate paths. It reads the SPEAKER NOTES only, because that is what gets said out loud (the
on-slide words are not spoken by anyone following PRE-FLIGHT 1, and counting both would punish the
decks that follow it), and it reports a BAND, never one number: 130-150 words per minute for a
word-delimited script, 180-220 characters per minute for CJK. A script it has no sourced rate
for and cannot segment — Thai, Lao, Khmer — is NOT CHECKED by name rather than given a number,
and a per-slide budget (10 minutes each / 每页 2 分钟) is read as no budget at all, because
taken as the talk's length it makes a correctly sized deck look twelve times too long. OVER THE SLOT blocks — with how many slides' worth of
speech to cut — while TIGHT, UNDER THE SLOT and ONE SLIDE EATS THE TALK (a page carrying more
than a quarter of the slot) are notes. No budget recorded, or notes on fewer than half the slides,
is NOT CHECKED and says which — a deck that will be READ is never late, and an estimate built from
a third of the talk is worse than none because it reads like a whole one. Waive in writing
({"talk_time": {"waived": "…"}}) when the slot really did change.
🔴 "PASSED" IS NOT "CHECKED" — read the COVERAGE line. Every gate run now ends with
[gates] COVERAGE: N section(s) ran — X bound, Y NOT CHECKED, one row per section that could not
bind and why. Measured, which is why it exists: three gates were silent on every deck because
nothing asked for the field they read, the template gate could bind to 1 of 11 registered
templates, and each was found by a human reading a transcript rather than by the tool. A row is
not a failure — a section that does not apply to this deck is correctly unchecked — but an
unread ledger is how a capability goes quietly unused. The Codex delivery gate prints the same
tally.
🔴 THE DELIVERED PDF NOW KEEPS ITS ALT TEXT, AND THERE IS A SPEAKER HANDOUT. --deliverables
exports through LibreOffice's PDF/UA filter: measured, the plain export produced a tagged PDF with
ZERO /Alt values, so every image description the a11y gate demanded stopped at the .pptx — in
the one artifact that gets emailed. It is a SEPARATE export from the render's: putting the filter
on the rasterization path changed a pixel check's verdict on another LibreOffice, so the render's
PDF stays plain and the accessible copy is made at hand-off.
It also writes <deck>-notes.pdf, one page per slide with the slide above its notes: this
skill requires speaker notes and reads them to estimate the talk's length, and then handed over
two artifacts in which they are invisible. A deck with no notes gets no handout and says so.
🔴 A PRESENTED DECK IS NAVIGATED, NOT JUST READ — and until now this library could not make one
jump. Measured: hlinkClick appeared only in _EA_FOLLOWERS, a constant listing XML element order,
and click_action in no file at all, so every "backup slide" this skill ever built was reachable only by arrowing past
everything in between — which is exactly why prepared answers go unused. dk.link (shape → slide,
shape/run → URL, scheme-guarded: a link target usually comes from the untrusted material the
deck was built from), dk.agenda(..., targets=[...]) (a contents page you can present FROM, and
the section-progress page a long deck repeats) and dk.back_link (the other half of a jump) close
it. Read references/navigation-and-qa.md whenever the deck will be presented live and the room
can interrupt — a defense, a committee, a conference talk, a board readout, anything with an
appendix. Record the questions you expect as content.qa
([{"question": …, "slide": <the backup that answers it>}], in both --init scaffolds) and
scripts/check_qa_backup.py checks the BUILT file on both gate paths: a backup slide nothing links
to BLOCKS (PREPARED BUT UNREACHABLE), as does a slide number the deck does not have, while
NO WAY BACK is a note. Nothing recorded is NOT CHECKED — anticipating questions is a practice,
not a law, and a gate demanding it of every deck would only teach authors to record an empty list.
🔴 AN ACADEMIC DECK CITES FROM ITS .bib, NEVER FROM MEMORY. Measured: nothing in this skill
ever read a bibliography — sources_page and source_note take STRINGS — so every citation it had
ever built was typed by hand, which is where a year drifts by one and a middle author disappears.
scripts/citations.py parses the BibTeX and derives both the in-text marker and the reference
line from the SAME entry (cit.in_text / cit.reference_page, numeric or author-year, with
etal=/amp= so a Chinese deck writes 等 and 与), and it REFUSES an entry with no
author/title/year instead of printing n.d. — under the never-invent floor a plausible-looking
citation is worse than a missing one, because nobody downstream can tell it from a real one. Record
content.citations (bib · style · keys in cited order) and scripts/check_citations.py
checks the BUILT file on both gate paths: a DANGLING MARKER and a cited key that is NOT IN THE LIST block, an UNCITED entry is a note. Read references/citations-and-bibliography.md
whenever the deck cites published work — it also carries the measured reason
reference_page sets the deck's link colour (a renderer paints a linked run in the THEME's hlink
colour whatever fill the run carries, so one references page came out half navy and half Word-blue,
decided by which entries happened to have a DOI).
🔴 Every section list was DERIVED FROM design-by-purpose.md's OWN PROSE, never invented —
teaching's objectives/example/recap were already in its Layout and Signature lines, the lab
meeting's "what changed" and "open questions" are its Signature line verbatim. Where a genre's prose
names no required section, none was added: a check that fires on good decks is how people learn to
ignore checks.
🔴 The thirteenth, webinar, has NO section list on purpose — it is a delivery MODE, not a
genre. The same session can be a lecture, a pitch or a readout, so a list attached to it would be
a guess about which. What it constrains is the MEDIUM, already held by the type floors and
formats.py's safe zones — and check_purpose recognises the medium words and asks you for the
GENRE instead of silently checking nothing.
Each genre also carries one fidelity rule beyond never-invent — a pilot stated as a pilot, open work
that reads as open, their claim separable from yours, a simplification flagged to a novice, and on a
clinical case de-identification, which is the one irreversible item on this page.
The review: question is NOT asked here — it moved to Step 5, after the first clean render.
It used to be a Step-0 axis, which forced the user to size a review of a deck nobody had seen;
with the rendered deck in front of them the same choice is informed instead of blind, and that is
what makes the cheaper default safe (Step 5 owns the question, its four options and the recording
rules). What Step 0 STILL decides is the research breadth, because research happens before
anything renders and cannot wait for the post-build question: derive it from the purpose —
standard for a lab meeting / status update / teaching deck, thorough for a defense /
conference talk / exec readout / pitch (the same two stakes classes the skill has always had;
purpose decides, deck SIZE never lowers it) — state the derived value in the Step-0 picks/plan,
and hand it to the planner at Step 1. Research narrows BREADTH only, never the fidelity floor:
every claim that reaches a slide is traced to a primary source at every breadth.
🔴 Read references/interview-protocol.md before you ask anything on a build ask — it owns the rest of Step 0: two-stage personalization from THIS user's footprint + taste.md precedence (🔴 MUST: current request > this interview's answers > taste.md), scaling the interview to the ask, Q1's four template choices (a)–(d) — all four MUST be offered, never a hardcoded institution — with each branch, Q2's delivery · deck-length · appear-builds · primary-goal axes + per-purpose cases + venue research, and Q3's source-material routing per input format.
One 🔴 CHECKPOINT lives in that file: the Q1(d) generated-template hero checkpoint (show the hero + a sample content slide, iterate until the user confirms). The Q1(c) direction gate (4 rendered directions) RUNS BY DEFAULT on the design-a-clean-one branch — skippable only via its named carves, and recorded on the design checkpoint's
direction gate:line.
- Their own deck, to improve (e.g. "redesign this", "my slides are too
dense", "make my deck better") → this is a redesign, not a build-from-scratch, and
it rewards a different front end. Follow
references/redesign-existing-deck.md: ask two extra answers in the same interview turn — keep your design/branding, or redesign the look? and how deep — light cleanup keeping your structure, or full re-author? — these REPLACE the Q1 template question (the R0 rule inreferences/redesign-existing-deck.md): keep makes their deck the template; redesign the look triggers Q1's four choices as a post-batch follow-up — and diagnose their deck first (render it, extract its content/figures withscripts/extract_deck.py, run the critic on it), then show the weakness list and confirm scope before rebuilding. Optimizing someone's existing deck rewards a diagnosis-led, scope-confirmed approach over a silent ground-up replacement.🔴 CHECKPOINT — show the diagnosis + proposed scope and get the user's OK before rebuilding their deck.
Q4 (style) — density levels, mimic modes, and the direction-gate scope are in references/interview-protocol.md (same file, later section). Read it before you offer the style question. It owns the three DENSITY levels (diagram-heavy / balanced / text-heavy, defined by text-per-point) and the mimic-a-style-example modes — two user choices that exist ONLY here, so if this file is not opened they get silently defaulted.
Language (decide it, then hold it). A deck is written in one language
throughout — default to the language the user writes in. When the source
material is in a different language than the user (e.g. an English-speaking user with
a Chinese codebase/paper), or it's otherwise ambiguous, ask which language the slides
should be in — don't assume the source's. When you ask the language, also offer
bilingual as an option (e.g. "English only, Chinese only, or bilingual EN+ZH?") so a user
who'd benefit doesn't have to volunteer it. Then translate the content into that language
and keep every slide consistent. Established technical terms, proper nouns, acronyms,
units, and code may stay in their original form (that's not "mixing"). Build a
mixed/bilingual deck only if the user asks (or picks it) — and then do it
systematically (same pairing on every slide). See references/multilingual.md.
Step 1 — Understand & plan the CONTENT (use the content-planner)
Use agents/content-planner.md for this step — the CONTENT only — dispatch
it through an available multi-agent/subagent tool when the host exposes one (in Codex,
discover multi-agent tools with tool_search if needed), otherwise run the same planner
brief inline yourself. On the design-a-clean-one branch, dispatch it in the SAME message that
posts the direction-gate link — the directions page carries no content, so the two waits overlap
into one (references/interview-protocol.md); the gate itself is unchanged and still blocks Step 2.
It is the
constructive counterpart to the critic/arbiter judges. Give it the interview answers
(purpose/audience/time, delivery context & primary goal, style/language, template
decision, venue if any plus the Step-0 venue-research findings — the planner builds on them
(re-verify, don't re-research)), the source material (or "none"), and the content references
(review-rubrics.md — the content lens — and multilingual.md), and the search cap: below. (The design references —
design-principles.md, design-by-purpose.md, form-selection.md, schematic-diagrams.md,
animation.md, image-generation.md — belong to the slide-design agent in Step 2, not here.)
It returns a Content plan — message only, no design: a comprehension brief + a claim ledger
- the authors'-emphasis check + the narrative arc (incl. the planned emotional curve + what's deliberately staged for later slides) + a per-slide CONTENT spec (takeaway that passes the memory test · role · question · beat · content units · visual source: which figure/number/data
- which question — what/how/why), plus flagged forward-looking content and open questions. You then take that plan into the Step-1 CONTENT
checkpoint (show it, get the user's OK on the story/message — the pace/slide-count check happens
HERE); only after content is approved does the slide-design agent design the look (Step 2). The
planner is one mind — it may fan out reading across multiple documents, but it synthesises the
understanding, arc, and per-slide message itself; never split one paper across blind agents. For a
quick, low-stakes deck you may do this pass inline yourself rather than dispatching — but
the deep-understanding and planning standard below is the same either way.
🔴 Each arc candidate carries a
serves_goalclause, and the competition is scored on the recordedinterview.goalBEFORE it is scored on elegance.arc_divergence.pyrequires the field and reports a set whose candidates serve the goal in the same words — that collapse is the field being satisfied rather than the competition being run. The order is the point: an arc chosen for being memorable and then checked against the goal is an arc chosen for being memorable.
🔴 The arc is COMPETED, not derived — 2–3 candidates over one ledger. The planner returns 2–3
candidate arcs (each naming its audience question, the objection it pre-empts, its closing ask and
the ledger ids it carries), you run python3 scripts/arc_divergence.py <arcs>.json, and YOU pick
— it is not a new user stop. The competition reaches the user as the content checkpoint's required
arc gate: line (picked + the losers + one clause each + the divergence verdict); a content
checkpoint without it is not ready. Rationale, both collapse modes, and the escape hatch:
agents/content-planner.md §3. This exists because the arc is the only decision whose error
invalidates everything downstream — a wrong form costs one slide, a wrong arc costs the design plan
and the build under it — and it was the one decision with no alternative on the record.
🔴 Its GATE is content.arc.candidates in .deck-gates.json — the candidate arcs THEMSELVES, not a
verdict about them. The hand-off gate runs arc_divergence.check() over them at delivery, so the
line you paste is no longer the evidence: it re-scores the set. Losers go in content.arc.rejected
(every one of them, with its clause) and a flagged-but-kept set needs
content.arc.divergence_justified. This changed because a delivered deck passed with
"divergence": "ok" — two characters — while the script had never been run for it; the previous
gate demanded the losers and their clauses, which raised the price of writing the record without
making it impossible. Both render_deck.py --gate-check and codex_delivery_gate.py recompute; a
run that skipped the competition now has nothing true to write, which is the point.
🔴 Hand the planner a search cap: too — and do the SMALL, NAMED lookups BEFORE dispatching it.
Web search is capped per SESSION, shared with every subagent, and it does not reset between decks in
one conversation. Measured: one research fan-out — 12 agents plus 7 verifiers, none of them told a
cap existed — spent all 200, and the bill arrived hours later when a single lookup for a company's
official logo could not run and that deck shipped without it. The cheap, late, small queries starve
because the big early fan-out took everything, so fix it in the order that buys the most: (1) run the
handful of NAMED lookups first — the logo, the brand colours, the one clearance number — since they
are few, they are exactly what starves, and Step 2 needs them anyway; (2) state a per-agent cap in
each dispatch prompt — an agent not told a cap searches until satisfied, and N of them do it in
parallel — keeping the whole round under about half of what REMAINS, not half of the original cap;
(3) carry searches: planned N / spent N to the hand-off cost: line. If the budget does run out,
say so on the deck's limitations page and in the hand-off: "could not verify" must never be allowed
to look like "does not exist" (full rationale at Step 5's SEARCH BUDGET block).
Hand the planner the RESEARCH breadth too — the purpose-derived value from Step 0 (standard
for the low-stakes class, thorough for defense / conference / exec / pitch). It sizes only the
research sweep; the REVIEW tier is chosen later, at Step 5, with the rendered deck visible, and
the planner neither knows nor needs it. What breadth narrows is BREADTH, never the fidelity
floor: every claim that reaches a slide is still traced to a primary source at every breadth. If
no derivation was recorded, the planner works at standard and says so.
The rest of this step is the specification the planner works to (and what you check its plan against). The bar — understand it deeply, don't skim:
A deck is only as good as your grasp of the material — a superficial read produces a
deck that looks right but misrepresents the work, which an expert audience spots
instantly. Read all of it, not the abstract: run the code's README, read the
paper end-to-end (intro → method → every results table/figure → conclusion).
(That end-to-end read is the default for a BOUNDED source; for a LONG source — a book /
very long PDF / large corpus — do NOT fake a single linear read: classify the size, then
run long-source mode (map → triage → deep-read the load-bearing ~20% + a blocking
Source-coverage map). See the long-source bullet below and content-planner.md §1.)
🔴 BEFORE any of that, write the AUDIENCE BRIEF — what the people in the room have to DECIDE,
in the order they will face it, each with what they need in hand — and aim the information
gathering at THAT list. It is a required field (content.audience_brief, checked by
deck_gates.py, --gate-check and the Codex gate from one contract in scripts/audience_brief.py)
and it carries an audience: line onto the Step-1 checkpoint. 🔴 On a deck with NO SOURCE it
REPLACES the comprehension brief: there is nothing to comprehend, so a brief written anyway is a
summary of the SUBJECT, and a subject brief ships a deck about the topic where one for the
audience was asked for.
Measured, twice, and the second time the rule already existed. (1) a Chinese request reading "a PPT introducing Paris" → a deck that correctly refused the Eiffel-tower motif and then also deleted the landmarks, the districts and the food, delivering an argument about 19th-century building regulation. (2) A Melbourne deck built from the recorded answers
audience = people planning a tripandgoal = they leave able to plan one: the Step-1 brief described the city, the three arc candidates were all generated inside that frame, and the winner was picked because "it is the only candidate whose organising idea also does the organising work … nothing is easier to remember a week later" — a DECK-QUALITY test. The recordedgoalwas never used to score them, and the practical candidate was rejected for becoming "the same list every travel site gives me" — which, for someone planning a trip, IS the deliverable. What shipped was a thesis on an 1837 land survey. The frame also aimed the RESEARCH: chains, allotment widths and inscription years were verified; daily cost, distances, a rainy-day alternative and what to skip were never asked for. Every gate passed. 🔴 Why the existing rule did not fire: the Paris lesson lives inreferences/checkpoint-convention.mdunder the delegated Step-0 picks, so it binds only under the auto-waiver. The Melbourne build ran a full interview and was never inside its scope. A correct rule in the wrong scope is not a gate — which is why the rule is restated HERE, where it binds on every deck, and why it now has a required field instead of a paragraph.The test, when you cannot tell: read the takeaway spine top to bottom. If it reads as a set of true statements ABOUT the subject rather than as answers to what this room has to decide, the frame is wrong — and patching a missing topic onto it (the Melbourne rebuild's first move was to bolt two landmark pages onto the survey spine) fixes the symptom and keeps the frame.
Then write a comprehension brief — a REQUIRED, fixed-field, source-traced artifact (the
planner's agents/content-planner.md §1 is the spec); every field must trace to a locatable
source span, not memory:
- The field list is in
references/content-plan-spec.md§Comprehension brief — read it before writing (or checking) the brief. It holds the one-sentence message + its verbatim source sentence, the contributions, the method essence, the one-row-per-figure-AND-table spec, the nuance/limitation quotes, and the claim-ledger columns (same spec asagents/content-planner.md§1–2).
🔴 Sweep the source for what IT says is NOT yet established, and record it — content.open_ledger.
Future work · next steps · a roadmap · an open gate · "cannot establish" · "not yet" · a TODO. One row
each: claim | where the source says so | absent from the deck, or stated AS OPEN on slide N. No row
may reach a slide in the established voice. This is a DIFFERENT failure from inventing and neither the
never-invent rule nor the claim ledger can see it: the fact really is in the source, promoted from
hypothesis to result, so it verifies clean and ships. Measured on a research deck: a slide asserted that
extra respiratory bins helped the reconstruction while the source listed exactly that as an untested
gate — the kind of thing an expert room catches in one sentence. [] is a legitimate value and records
that the sweep happened (a no-source deck writes []); BOTH gate paths block the missing KEY and never
the count. Field spec: references/content-plan-spec.md.
This is a hard gate, not a sanity check. Self-verify the brief against the source; if any field is empty, hedged, or untraced — or the emphasis test fails (your one-sentence message would surprise the authors) — you have NOT understood it: re-read or log an open question. An incomplete or untraced brief blocks the build. Every slide must be faithful to the authors' actual emphasis, not a plausible-sounding paraphrase. Reuse their figures (relabel for the slide).
Having a source is rarely the whole story — use the web for the gaps, even with one. Most decks are partial: a paper that needs related-work-since-publication or current framing, a code repo with no writeup, figures with no prose, a doc that omits the venue. So the web step below is not only for the "No content" case — run it whenever a source leaves a gap, and in particular re-verify the source's own falsifiable / time-bound claims at today's date: a paper's "state-of-the-art", an adoption number, a "first/largest/ latest" superlative may be stale by presentation day. Re-verifying a source claim is not inventing — it's fidelity to what's true now.
-
No content — and any web fact-check on any deck: draft the outline from your own expertise, then ground and verify every falsifiable claim against a primary source, and ground the deck to today. Read
references/content-plan-spec.md§Web verification & no-source decks before running any search or putting a falsifiable/time-bound claim on a slide — it owns the PROVENANCE CONTRACT, the re-verify-on-every-build list, the dated-event tense rule, and the no-web-tool fallback. 🔴 A web pass ships on three floors (content-planner.md§2(e)): COMPREHENSIVE (map the domain, sweep breadth-first, + a proactive LIFECYCLE sweep — every featured product/version/entity checked live-vs-discontinued as of today, so a dead/renamed thing is never headlined), SUBSTANTIAL (every load-bearing slide carries a concrete number/date/price/named result, not adjectives), ACCURATE (each fact corroborated ≥2 independent credible sources — content-farm blogs corroborate nothing; confidence-tagged; MED facts ship only when labelled "per public reporting"). The content checkpoint MUST then carry thecoverage:·lifecycle:·provenance:lines, or it is NOT READY (the content-planner §1 web-research gate +checkpoint-convention.md). Measured: a no-source deck shipped thin and headlined two discontinued products because none of this was enforced. -
A long source (a book / very long PDF / large corpus / multi-volume set) is NOT read front-to-back — a faked linear read either overflows or, worse, fits and goes shallow. The moment a source might exceed ~40–50 pp or not fit one pass, read
references/content-plan-spec.md§Long-source mode — deterministic size classification (extract_pdf.py map, CJK counting, multi-file sum), structure map, triage, the verbatim ~20% deep-read with page-traced claims, page-scoped figure locators (never whole-documentautofig), the Source-coverage map, the TWO-PHASE dispatch that posts the selection FYI before the deep-read, and the scanned/DRM no-text case.
End Step 1 at the 🔴 CONTENT checkpoint — pace-check first, then approve the story. The
Content plan is the cheapest place to fix a misread or a wrong emphasis, so present it before any
design begins: the comprehension brief + claim ledger FIRST (so the user can spot a misread
before a single slide is designed), then the authors'-emphasis check, the narrative arc,
and the per-slide takeaways + content (message only — no look yet), plus any flagged
forward-looking content and open questions. The pace / slide-count check happens HERE, not
later: for a spoken deck scale the slide count to the time budget — ~1 slide per talking-minute
as a loose anchor (short talk/status ~6–9, lecture/thesis defense/job talk ~10–20+), counting an
animated/build slide once; compute slide_count ÷ time_minutes and, if it runs well over ~1/min,
cut slides or get more time and flag it. A read-alone / poster deck has no talking-minute budget —
its scope is set by content completeness, and deliberate density is fine, not a defect. Confirm
the resulting slide count with the user (never ship a length they never saw). For a long source
(book / very long PDF), the checkpoint ALSO carries a DIGEST of the Source-coverage map (the chosen
slice + a built-around/summarised/cut tally; the full per-chapter map stays in the plan) and
confirms the SELECTION. Ordering matters: the verbatim deep-read that produces the verified ledger
happens inside Step 1, so the wrong-slice must be caught earlier — the planner surfaces the coverage
map as a cheap selection FYI right after mapping+triage, before sinking the verbatim deep-read,
and it is re-confirmed here before DESIGN and BUILD (Step 2+) commit. The wrong-slice risk is the
biggest one at book scale, so it is surfaced even under the auto-waiver (as an FYI). Precondition —
the comprehension gate: before showing the plan, confirm it carries a complete comprehension
brief (every field filled + traced) and claim ledger (no shipped verified? = N rows), a
Takeaway spine that reads as one argument (an incoherent spine is "not ready" — send it back to
the planner), a scripts/plan_wordcount.py pass over the per-slide table (advisory — but an
over-budget row with no recorded "over budget → notes/split" resolution goes back too), a
source size: line on any file-sourced deck (the bounded-vs-long classification must be a
recorded measurement — its absence means the classification never ran), for an over-threshold
long source a complete Source-coverage map (a disposition for every skeleton section — the
map TOC or the recorded reconstructed skeleton, every file for a multi-file source — + the
verbatim-vs-skimmed line + the selection FYI: line; a missing/partial map is "not ready"), and
for a video-sourced deck the transcript-status line (supplied locator or the visual-only GAP
line); an empty/hedged/untraced brief is not ready — send it back to the planner. Fold in the
user's edits to the story, then move to design (Step 2).
🔴 CHECKPOINT — CONTENT: show the comprehension brief + claim ledger + narrative arc + the per-slide takeaways/content, and confirm the pace/slide-count, before any design work begins — rendered as the compact ≤~25-line checkpoint artifact defined under the 🔴 CHECKPOINT convention (the brief + ledger appear as its 2-line digest; post the full versions on request or on any digest anomaly — unverified rows, open questions). For a long source (book / very long PDF), the artifact also carries a DIGEST of the Source-coverage map (chosen slice + a built-around/ summarised/cut tally; full per-chapter map in the plan) and the SELECTION is confirmed here — the coverage gate at book scale (also surfaced earlier as a cheap FYI, before the verbatim deep-read).
Step 2 — Design the deck (use the slide-design agent)
🔴 OPEN STEP 2 BY READING WHAT THIS USER HAS ALREADY TAUGHT
python3 scripts/taste_ledger.py list --binds-at design --format promptCorrections the user made by hand on earlier decks live here — icons missing on categorical content, a deck that came back as grey blocks, a motif louder than the content it carried, a type default they set themselves. Without this the same note arrives deck after deck, each one costing a delivery to rediscover; the user becomes the skill's memory, and pays for it every time. An empty ledger asks nothing (a fresh install has one, and that is the normal case). When it is not empty, record one row per active entry in
design_plan.taste_applied—{"id": …, "applied": true}or{"id": …, "applied": false, "why_not": "<why it does not bind here>"}. The gate checks that each was considered, never that it was obeyed: a taught rule can be right to break on this deck, and a skip written down is design (this is the taste protocol's rule 3 applied to the user's own corrections). Learned something new at hand-off?taste_ledger.py add --id … --quote "<their words>" --rule … --binds-at … --deck …— the quote must be theirs, or the rule is something you decided and attributed to them. And when a rule earns a deterministic check,retire <id> --gate <CODE>: entries leave by being promoted, not forgotten, which is what keeps the ledger from turning into noise.
🔴 STEP 2 IS BRANCH-INVARIANT — it runs IN FULL on EVERY Q1 template choice
The Q1 choice — (a) design-a-clean-one, (b) a provided template, (c) the direction gate, (d) a generated visual identity — decides only the LOOK SOURCE. It NEVER removes the design plan or its 🔴 design checkpoint. A branch's look-gate confirms the LOOK, not the per-slide DESIGN: the branch-(c) direction gate and the branch-(d) hero checkpoint are NOT the design checkpoint (the per-deck auto-waiver lists them as separate stops for this reason). After either, you STILL produce the design plan (form ledger · rhythm · signature move under a boldness dial · the 3 design musts · semantic colour · density · logo/motif) and post the design checkpoint — with its
direction gate:(c) /style gate:(d) line — before building. A generated identity feeds the plan (palette / motif / surface / type are inputs, recorded as the four-line contract); it does not replace it. Enforced deterministically:render_deck.pyREFUSES a full render when a content plan is recorded but no design plan + design checkpoint is (a--slidesprobe render is exempt, and it reads both the shared.deck-gates.jsonand the Codex.codex-deck-evidence.json) — so the plan can never be reconstructed post-hoc to pass the hand-off gate. This closes a measured regression: the generated (d) branch's workflow once routed interview → build and let its hero checkpoint stand in for Step 2, shipping a deck whose layout, rhythm, and forms were never planned or reviewed.
🔴 STEP 2 OPENS WITH A MATERIAL PROBE — one REAL slide, built and looked at, BEFORE the plan is written
Author the signature page in the invented register with real deckkit, render it, and LOOK at it — then write the design plan's declarations to describe what you made. Not after. The plan is a description of an artifact that exists, never a promise about one that does not.
WHY, measured on a delivered deck in this repo's own history. The pipeline gates a motif's CONCEPT thoroughly — a derivation ladder with two middle rungs, two rejected pictures with the clause that lost each, the STRANGER TEST, ONE-form-ONE-meaning, the generativity triple — and its MATERIAL not at all. On that deck the concept was genuinely right (a config row, derived from the product's own
cordis.yml, correctly rejecting the plug-socket stereotype every plugin deck reaches for) and it passed every one of those checks. What shipped was six grey rectangles. The user's verdict was that the design had got WEAKER. The repair changed only the material — the same rows became a real config with keys, values and a-/+diff — and nothing about the concept moved. No step between "concept approved" and "deck delivered" had asked what the device is MADE of.The cause is an order-of-work failure, not a missing rule: the design turn had ~20 required declarations and zero required artifacts, so the effort went into sentences that pass instead of a thing that works.
signature move: the cover demonstrates the argument itselfis a good sentence and it was true of nothing on the page. Pixels cannot be faked this way — a grey-bars register renders as grey bars — which is the whole reason this probe comes first.
- Build ONE slide: the page the signature move lands on, in the register you just invented, using the same
build_<deck>.pythe deck will use. Render it (render_deck.py … --slides 1).- Look at it, and answer one question in one line: what would the SAFE version of this page have been? If the honest answer is "about the same thing", the register is a look, not a move — go back and invent, before twenty declarations are written on top of it.
- Then write the design plan. The checkpoint carries a
material probe:line — the rendered PNG plus that one-sentence comparison.Cost is one build + one render (seconds), and the page is not a throwaway — it becomes the deck's signature slide and serves as the Step-4 anchor proof's
signatureanchor, so the ritual is paid once. It is a different question from the anchor proof, which asks whether the move SURVIVED the build; this asks whether the register was worth building at all.Skip only when the look is not yours to invent: a registered/provided template or a Mode-A mimic (the material is the template's), or a 1–2 slide tiny ask.
boldness: conservativedoes NOT skip it — restraint is a material decision too, and a page is exactly where you see whether it reads as deliberate or as nothing.
With the Content plan approved, first build the Evidence manifest — one READ-ONLY probe line per asset the approved plan names, so the art director plans geometry with its eyes open (a no-asset deck skips it entirely). Read references/asset-production.md §Evidence manifest before dispatching slide-design for the line format, the probing tools, and the rule that probing NEVER materializes crops/equations/plates (asset-prep still runs only after the design plan is approved). That file is the asset lifecycle end-to-end — probe → image opt-in → crops → charts → logo/icons → equations.
The per-asset SPEC asset-prep consumes has a named producer: the Design plan's per-slide rows
(or its image opt-in list) carry, per asset, the crop spec (or autofig index N — but on a
long-source deck the locator must be page-scoped: figures <src> <page> + the caption label,
never a whole-document autofig index, whose global numbering shifts between runs), a generated
plate's topical prompt, an equation's target height, and a GIF's poster frame — and where the
approved plan left one implicit, the COORDINATOR completes it from the plan's own geometry when
assembling asset-prep's work order (asset-prep itself never decides these; it only executes).
Then dispatch agents/slide-design.md — the deck's art director
— to design the look on top of the locked message. Dispatch it through an available multi-agent/
subagent tool when the host exposes one, otherwise run the same brief inline. Give it the approved
Content plan (comprehension brief, claim ledger, narrative arc with its emotional curve, and the
per-slide CONTENT table with each slide's role · question · beat and visual source cells),
the Evidence manifest (asset geometry, above), the taste lines —
taste.md's DIALS + NO-GOs + its LAST look-history line, read from the registry root per
references/user-taste.md ("none on file" for a brand-new user) — so §1 Freshness has something
real to vary against and the chrome-budget default is seeded, while the interview's explicit
answers and the LOCKED-look carve always outrank them, the
interview answers that steer register
(purpose/audience/time, delivery mode, style, template/brand decision, venue — plus, when the user
gave a Q4 style example, the written style brief + chosen mimic mode), and the craft
references it designs against (form-selection.md, design-gallery.md, scripts/presets.py,
design-by-purpose.md, design-by-topic.md, bespoke-registers.md, design-principles.md, design-intelligence-addendum.md, semantic-color-contract.md, data-viz.md,
schematic-diagrams.md, icons.md, animation.md, image-generation.md,
east-asian-aesthetic.md — and, for a mimic deck, style-analysis.md). It consumes the approved content — it does not reopen it — and
returns a Design plan: the deck's Design language (a named signature motif + a
deliberately-chosen palette/type + the polish moves), the deck rhythm, a per-slide design
table (form + the runner-up it beat · reasoning · layout · motion · image?), the
Form ledger + diversity gate, the design self-verify checks, the 10-item design-critic
checklist (which the Step-5 critic's design lens then applies), and the image opt-in list. The
art director is one mind over the whole deck — only it sees every slide at once, so deck rhythm and
where the appear-builds fall are its call, not the builder's.
The design plan is the cheapest place to change visual direction, so end the step by showing it
and getting the user's OK before the canvas is set up or anything is built. This design intelligence
runs on EVERY deck — it's how the art director designs, never opt-in per deck — and scales down
gracefully to small decks (a 4-slide deck still earns one hero per slide, no card-grid reflex, semantic
colour, and one memorable moment); only the deck-level numeric floors are size-gated (hard at ~8+ content
slides, strong guidance at 6–7). Precondition — the design gate: the plan is not ready unless it carries a concept: line
— what this deck's idea is a PICTURE of, the two middle rungs that produced it (via <core concepts> → <visual language>), plus the TWO pictures it beat and the clause that lost each
(the ladder is topic → core concepts → visual language → motif; the MIDDLE rung is the one that
gets skipped, and skipping it is what produces industry stereotype — an MRI deck jumped straight to a
picture gives you a scanner, routed through frequency · sampling it gives you a k-space grid. A
winner with no rungs is a picture that arrived, not one that was derived. Full ladder + the
domain-neutral §3 dictionary it resolves through: agents/slide-design.md §1.
🔴 This rule governs the MOTIF, never the CONTENT. Rejecting the obvious PICTURE is the job;
dropping the obvious SUBJECT is a different act and it is almost always wrong. Measured: asked for
a Chinese request reading "a PPT introducing Paris", a run correctly refused the Eiffel-tower silhouette as a governing image — and
then also deleted the landmarks, the neighbourhoods and the food from the CONTENT, delivering an
argument about 19th-century building regulation to an audience that came for a city introduction.
A deck may carry Notre-Dame, the Louvre and Montmartre while its visual language owes nothing to a
postcard. Give the audience what they came for, in a form no template would have found — that
is the whole sentence, and taking only its second half produces a deck that is distinctive and
useless.)
(an intelligence network · a digital organism · a hand and a machine hand doing one job — three
governing images for the same approved argument, not three styles and not three layouts). This is the
one divergence the pipeline never had: the direction gate diverges on STYLE (its own preview page says
"the same four slide types … only the style differs") and form-selection diverges on LAYOUT per
slide, and both hold the picture constant. The motif does not fill the hole — it is chosen as an
attribute of a preset picked first and capped at ≤3 appearances, so a governing image is structurally
forbidden from governing. It costs three sentences at plan time: no extra dispatch, no extra render,
no extra round trip (agents/slide-design.md §0). One picture with no alternatives is not a choice,
it is the first thing that came to mind — and the hand-off gate rejects two "alternatives" that are
the winner in other words. It also has a concrete Design language (a named
signature motif + a deliberately-chosen palette/type, not a defaulted light/minimal/blue), a one-line
taste-profile field in that Design language section — taste profile: <n dials applied / none on file> · freshness: varied <foundation> vs <last look-history line>, or the alternate arm look LOCKED (registered/provided template) — carve applies — the line that makes the freshness rule
checkable and any profile override visible (references/user-taste.md), a boldness: line
(conservative | balanced+ | bold | experimental — DERIVED, not a flat default: explicit user
request > taste.md's promoted dial > the purpose — conservative for a sober defense / regulatory
/ status readout unless asked otherwise, bold for a pitch / launch / brand / culture deck,
balanced+ for everything else; record which arm set it (agents/slide-design.md owns the full
table). This derivation used to live ONLY in the art-director's own file, so an inline run — which
never opens it — gave a launch deck and a status readout the same middling dial, and then judged
both against it: the pitch was never asked to be brave and the status readout was told off for not
being. Layer 1 has to carry the mapping because layer 1 is what an inline run reads; at conservative the risk is
OPTIONAL — take a modest restrained move, or fill the field with the one-clause deliberately restrained: <why>, and then signature_proof is not required because there is no risk to prove.
Every other field still is, and above conservative a real move is required, not optional) AND a real signature move:
line — the ONE deliberate aesthetic RISK a template wouldn't make, scoped to where it lands (cover /
WOW / money slide) and adapting a named bold reference, plus a carried_by: clause naming 2–3
slides (the signature slide + ≥1 more) where the same idea does STRUCTURAL work — one brave slide
among nineteen safe ones reads as a tonal break, not a position; coherence is what makes daring look
deliberate. Carried means the idea becomes the shape of the content on those slides (the motif
turns into the diagram's own geometry), not a decorative repeat — a device stamped on every page
is the opposite failure and the motif budget (≤3 appearances) still binds; a signature move that reduces to "a big
number / a nice gradient / a full-bleed photo" is the safe catalogue, not a signature move, and
makes the plan incomplete (send it back; self-verify (h) owns this) — only boldness: conservative
(whether user-set or purpose-defaulted) makes the risk optional, softening the field to a named
"deliberately restrained" clause so it's never blank; the risk lives on
composition/scale/concept/type and never overrides a floor (legibility/fidelity/lint win), an
AR a.b -> <zone> annotation in the Layout cell of every slide placing a manifest-listed
figure/table (a plan that commits a known-geometry asset to a zone without checking the fit is
not ready — send it back to the art director; the slide-design §3 Image-fit rule owns the
re-form-vs-taste-reason call), a Form
ledger whose diversity gate passes (no one format-family on >~40–50% of content slides — the
card-overuse guard), the addendum's deck-level design gates — a rhythm map, a semantic-colour
ledger, a passing block-dependency audit (no >2 consecutive card slides), and the minimum
deck-level variation (references/design-intelligence-addendum.md) — plus, on ANY deck that NAMES
a real entity (not only a single-entity one: a company / product / brand / institution / government
body as the SUBJECT, a tool/framework/model named as content, or a slide whose FORM is a roster of
named real entities — an ecosystem map, an alliance's member list, a comparison whose rows are
institutions), a logo plan WITH EVIDENCE per the slide-design LOGO PRINCIPLE's situation
table: the line must read official asset — <source>, searched, none found → designed wordmark (flagged), or n/a — <named inline as text | template carries it | user opted out | third-party assessment>
— and a roster slide additionally carries entity marks: <N of M sourced | none — reason>, because
one line cannot say both "the deck's own mark" and "the eight institutions on slide 5". 🔴 A generic
placeholder glyph in a mark's slot — a coloured square, a repeated stock icon, a bullet dot dressed as a
crest — is NOT an acceptable value for that field. It is decoration impersonating information and it
fails the 1-second decodability floor; plain type beats a shape that looks like it means something.
(Measured: a 12-page deck listed all eight Go8 universities around a hub — the exact ecosystem-map form
the LOGO PRINCIPLE says earns a logo wall — and shipped eight identical blue squares. Nothing was wrong
with the rule; the deck was multi-entity, so no logo plan: line was ever required, and a rule nobody is
asked to evaluate is a rule that does not run.)
— third-party assessment is a full member of this set, not a footnote: it is decided BEFORE the
search and overrides its result (the 🔴 row below), so a deck that qualifies for it must be able to
name it here — a bare "wordmark"/
"text only" with no recorded search, or a missing line on any deck that names a real entity (including a roster slide), makes the plan
incomplete (send it back; self-verify (o) owns this) — and the THREE
DESIGN MUSTS addressed (slide-design.md's three design musts) —
(1) appear-builds — ONLY if the user opted in (the interview's presented-deck choice): if IN, a
motion manifest places builds where they help (build/static with a reason per slide) and each built
slide is staged FULLY (every content element in a step, deliberate order); if OUT, every slide is
static: user opted out and that is complete, not a gap. (2) a style-matched SVG icon family — 🔴
icons are the DEFAULT on any deck with categorical / multi-item / conceptual content (a roster,
a set of pillars/roles/tools, a 3-item preview, a step list): they aid the 1-second read and reinforce
the visual system, with no cost worth their absence, so the question is never "should this deck have
icons" but "which slides earn them" — every branch, incl. generated-template (self-verify (g); "opt-in"
never waives it). Skipping the family is a HIGH-bar choice, not a casual one: icon_family: none
must classify WHY from four reasons where an icon family would genuinely HURT — motif-dominant (a
strong constructed motif icons would dilute, the ≤3-loud budget), editorial-register (a data/editorial
register — FT/Economist — icons would cheapen into corporate), tiny-deck (a 1–2 slide ask), or
template-locked (a provided template that carries its own marks) — recorded as
🔴 A FIFTH category exists: user-declined — the user asked for no icons. The four above each
make a claim about the DECK, and none of them can say the user decided, so a deck whose user said
a Chinese "no icons needed" instruction had to be filed template-locked — a different claim, and one the Codex gate VERIFIES
against the built file, so the forced label can also fail for the wrong reason. It is their deck; a
gate has no standing to second-guess that, only to record it. icon_none_checked still names every
flagged slide.
🔴 The category is a claim about PAGES, not about the deck — and it is VERIFIED against the
built file (motif-dominant needs a real loud motif in the file, tiny-deck a real tiny deck,
template-locked a real template). A deck-level reason may not cover pages the reason does not
reach: motif-dominant on a deck whose roster pages carry no motif at all is the measured failure
— a coherence argument overriding a stated default with no per-page test, and the first human
reader's first note was "icons should be here". Re-decide page by page; the honest answer is
usually neither zero icons nor an icon everywhere, but icons on the pages where they do work
nothing else on the page is doing (three DIFFERENT KINDS of fact side by side; the one row a
reader scans FOR an item) and none where another element already encodes the distinction (a
position map, semantic colour, numbered routes, the motif itself).
design_plan.icon_none_category + icon_none_checked: [slides] (Codex: an icon waiver with
category). A bare "not category-rich" no longer clears it, and the category explains the REST of the
deck — it is never a licence to drop icons from the categorical slides that do have them (a
motif-dominant deck may still put icons on its one roster/preview page, as this skill's own UK-labour
deck does on its two 3-item slides). 🔴 But icons must ENCODE, not decorate — a topic-stamp beside
a lone big number or a single statement is decoration that fails the 1-second-decodability floor
(design-must-be-meaningful); the default is "icons on the categorical/conceptual slides," not "an
icon on every slide." (3) diverse formats (not a card grid repeated) — musts 2–3 are
applied where they help or justified where not (a must to consider + apply, never a blank per-slide
quota — still smart about where/when). A plan that defaults its look, over-relies on one format, forgets
icons, or — when builds are opted in — leaves a built slide half-staged or forgets builds where they'd
clearly help is not ready — send it back to the art director.
Codex only: include references/codex-runtime.md in the art-director brief and begin its hidden
.codex-deck-evidence.json once the design direction is known. Its per-slide ledger must mark which
slides are categorical, bind those to one actual icon family or a slide-specific waiver, and name any
early component carve; do not let either decision disappear into the builder's convenience.
🔴 One row of the LOGO PRINCIPLE table decides BEFORE the search and overrides its result: a
THIRD-PARTY ASSESSMENT. The deck is about an entity but is not from it, and carries what that
entity would not publish about itself — open recalls, a "first but not unique" correction, a
limitations page, competitor counter-evidence. There the answer is n/a — third-party assessment
plus the finding that makes it so: no official livery on any page, the entity's name set in the
deck's own type. The test is authorship, not sentiment — a favourable independent review has the
same problem as a critical one. A reader seeing the mark concludes the entity produced or endorsed
this, and for an independent assessment that is a misattribution: the same class of error as an
unsourced number, committed in the chrome instead of the body. Because it is a question about who
wrote the deck, finding a real logo does not overturn it and "not found" is never its reason.
(Real: a briefing carrying two open Class I recalls and a "first, but not alone" correction was
headed for build in its subject's brand colours; it was caught by hand and recorded as a named
deviation. This row makes that the default instead of a save.)
The per-slide content-image opt-in is a CROSS-CUTTING choice available on EVERY deck — independent of the template decision and separate from Q1's generate-a-template path; offer it whenever an image tool OR web search for sourced photos is available. Read references/asset-production.md §Per-slide content-image opt-in before writing the opt-in list — the three guardrails (content-related, never every slide, and the REFERENT RULE that decides generated vs real sourced imagery) and the per-row source-token grammar. Fold in the user's design edits, then set up the canvas (Step 3).
🔴 CHECKPOINT — DESIGN: show the
concept:line (the governing image + the two middle rungs that produced it —via <core concepts> → <visual language>— + the two it beat, each with the clause that lost it) + the Design language + Form ledger + the 3 design musts + theboldness:line + thesignature move:line with itscarried_by:clause (the one scoped aesthetic risk + where it lands + the bold reference it adapts + the 2–3 slides where the same idea does STRUCTURAL work — so a wrong dial, a timid/too-wild move, or a risk that lives on exactly one slide costs one glance to veto) + the image opt-in list (each row with itsgenerated — <tool>/sourced — <origin> (<license>)/provided — …/searched, none found → …rung — full grammar:references/image-generation.mdstep 5 — source token) + (on ANY deck naming a real entity — subject, named-as-content, or a ROSTER slide) thelogo plan:line WITH its evidence token (official asset — <source>/searched, none found → designed wordmark (flagged)/n/a — <reason, incl. third-party assessment>) + the **motif line stating the device AND its meaning
- how it's made legible +
motif generates:(background · markers · one PAGE whose geometry IS the motif —none — <reason>beats an invented artifact) + ONE MEANING PER REPEATED FORM deck-wide** — the last two are gates, not garnish: a motif that only recurs is an ornament with a schedule, and a device meaning one thing on the cover and another inside passes every per-page check while still sending the reader asking what it means (measured twice, on two different decks). On branch (c) both are REQUIRED rather than weighed, because there the motif IS the deck's visual design;conservativeand a 1–2 slide tiny ask carve out, and on a locked template the ladder is not re-run on its device (label / legend / figurative / removed — the STRANGER TEST; a motif may be a CONSTRUCTED OBJECT rather than a shape — something this deck's own material would BUILD, gaining a part per beat instead of appearing again per beat, which is what makescarried_bystructural rather than stamped. Derive it from this content; there is deliberately no menu, because a menu of objects becomes the next house style. The test: could this object belong to any other deck? And it is the right answer only when the argument ACCUMULATES — a comparison, a set of independent findings, or a sober regulatory register wants the abstract device instead, and picking that deliberately is the same judgement working, not a failure to be bold. Full when/when-not:agents/slide-design.md; a reading that DEFERS to a later slide is a failed test written as a passing sentence) + theinterior register:line (the quiet cue that carries the style onto ordinary interior pages, ornone (flat by register — <reason>)— self-verify (q) · PRE-FLIGHT 6b · the critic'sregister_interiorscheck all read this field, and a style dressed only on the bookends fails) + thedensity:line as two numbers — presented as the compact checkpoint artifact from the 🔴 CHECKPOINT convention block (same fields, incl. the rhythm-map table and the branch gate line —direction gate:on branch (c),style gate:on branch (d); picked look or named carve) — and get the user's OK before building.
Step 3 — Set up the canvas
First, decide where the deck lands. Deliver each deck as one self-contained
folder in the user's Downloads — ~/Downloads/<deck-name>/, holding the
<deck-name>.pptx and a render/ subfolder of slide PNGs — so the user gets a tidy,
findable bundle rather than a stray file in /tmp.
🔴 The .pdf and viewer.html are NOT produced during the build. A deck is iterated
— rebuilt each critic round, then usually hand-edited in PowerPoint — so a PDF and a preview
page generated on every render are churn: they clutter the deck root and go stale the moment
the .pptx changes, which is worse than absent (a user opens a stale PDF and reviews the wrong
deck). They are reserved deliverables: at hand-off (step 6), once the user confirms the deck
is final, offer them and generate both with render_deck … --deliverables. Point your build script's
output path and render_deck.sh's out-dir there from the start (no need to copy
files around at the end). Before the first save, confirm ~/Downloads exists; if
it doesn't, ask the user where they'd like outputs and use that location instead —
don't silently dump into /tmp. You'll remind them to open it in step 6.
🔴 CHECKPOINT — if
~/Downloadsis missing, ask where to save before writing any file. (Per-deck auto: this checkpoint is a question, so it has no FYI form — do not stop. Default:mkdir -p ~/Downloadswhen the home directory is writable (keeps the standard~/Downloads/<deck>/layout every reference assumes); only if home is unwritable, use./<deck-name>/in the working directory. Never/tmp. State the chosen location in chat the moment you decide it — auto mode is never invisible — and repeat it in the hand-off.)
🔴 The moment you have a folder, DISPATCH THE IMAGE MANIFEST — then keep working
Generated plates are the slowest thing in this pipeline (~30–90s each, and the scripts run them concurrently). Authoring the build script is the longest thing YOU do. They are independent: generation is waiting on a hosted model, authoring is you writing Python. Run them at the same time. Put every approved plate — hero, dividers, interior, per-slide — into ONE manifest, start it, and go straight on to the canvas and the build script without waiting. By the time you execute the script the images are on disk, and you paid for them in wall clock you were spending anyway.
- The build RUN is the barrier, not your judgment —
python-pptxraises on a missing image file, so a script executed too early fails loudly and names the file. There is no version of this that quietly ships a deck with holes in it.- The one thing that genuinely blocks: the signature slide's assets. Step 4 opens with the SIGNATURE PROOF, so
asset-prepdelivers that slide's plate/figure/icons first (its brief already says so). Everything else can land while you author.- Order the manifest to match: signature slide first, then the rest.
- Do not dispatch before the Step-2 DESIGN checkpoint is approved — the prompts, placements and opt-ins are exactly what that checkpoint locks, and regenerating a rejected plate costs more than it saved.
(Serial by default was never a decision anyone made — the pipeline simply read top-to-bottom. Measured cost of leaving it serial: the full generation batch, dead, before authoring starts.)
Canvas format. The default deck is 16:9 via deckkit.blank_deck() — untouched, and everything below assumes it. If the interview confirmed any non-16:9 surface (4:3 venue · rednote 3:4 · square 1:1 · story 9:16 · A4 print · A0/A1 conference poster, portrait or landscape) — or the design plan carries a format: line that isn't wide — read references/deck-setup.md §Canvas format BEFORE creating the presentation object; it carries the scripts/formats.py contract (band safe rect · chrome · columns_ok · display_scale · lint_flags) and the rule that the design plan records a format: line whenever it isn't wide. 🔴 The registry is no longer advisory: scripts/check_surface.py recovers the format from the built canvas and enforces the contract at hand-off (--gate-check section surface, and the codex gate) — platform-UI safe zones, the columns_ok rule, deck chrome on social surfaces, and for a PRINTED board the absolute three-distance type floors and fill range. A poster is not a big slide: it is read at ~5m / ~2m / ~1m, so A0 declares display ≥90pt · section ≥36pt · body ≥24pt as ABSOLUTE points (deckkit's cover caps titles at 46pt, right on a 10in slide and unreadable across a hall on a 33in board), a fill range of 55–90% of the board covered, and methods + limitations as required content — the billboard style that draws people in is the style that drops the two things a passer-by cannot reconstruct. Waive either in writing (design_plan.surface_sections_waived). It also holds a PROPORTION floor — the poster literature converges on ~20–25% text / 40–50% graphics because a board is read standing by someone deciding in seconds, and a panel drawn behind text counts as a container, not a graphic — a TEXT BLOCK ceiling at ~50 words, and deckkit.qr_panel() for the code, its caption and the plain-text URL a photographed poster still needs — it sizes both from the CANVAS (so they clear the printed floors), takes its scan distance from the surface, and refuses a placement that would run off the board. 🔴 A printed board must not go dark: check_register_pixels.py reports DARK GROUND ON A PRINTED BOARD, and the freshness rule below changes its advice on a printed surface (vary the paper and the accent hue, never the value).
Keep the per-deck build script (build_<deck>.py) in that same folder, beside the
.pptx. The build script — not the rendered file — is the source of truth for the
deck, so it should travel with the artifact: this makes every later iteration
reproducible (re-run it, get the same deck) and is what lets you fold the user's
later change requests back into the build rather than hand-patching the binary. See
references/handoff-and-iteration.md for why this matters at hand-off and how to
iterate without clobbering the user's manual edits. In that script, resolve deck assets
relative to the script file (for example ROOT = Path(__file__).resolve().parent) rather
than the current working directory, so python /path/to/build_<deck>.py works from anywhere.
-
Template branch — the user supplied a
.pptx, or Step 0 found an official conference template: readreferences/deck-setup.md→ "Template branch" BEFORE creating the deck object (inspect →open_template()→ adopt the template's brand → register a reusableprofile.md). 🔴 A registeredprofile.mdis now CHECKED against the deck you build, not merely available to read. Give it one fenced## Machine-checkable contractjson block — any ofmatch(the layout-name + canvas-size fingerprint this binds by),layouts,fonts,title_color,must_cover— andscripts/check_template_profile.pyholds the built file to it on BOTH gate paths (LAYOUT OFF PROFILE·FONT OFF PROFILE·TITLE COLOUR OFF PROFILE·UNCOVERED TEMPLATE FURNITURE; waive with{"template_profile": {"waived": "<why this deck differs>"}}). It binds by the DECK's own fingerprint rather than by a recorded template name, so a runtime that compressed the interview away is still checked; a profile with no contract block reports NOT CHECKED, never clean. Why it exists: the registry is the one artefact here with a MEMORY across decks — the layout indices, the decorative rectangle that cannot be deleted and must be covered, the font trap someone already hit — and measured by grep it was read by two producers and by NO check, so a build could ignore every line of it silently. When you learn something new about a template, add it to the prose AND, if a machine can decide it, to the contract. -
No-template branch — you are designing the look yourself: read
references/deck-setup.md→ "No-template branch" BEFORE the first palette/preset/font call. Reach forpresets.apply("<name>")— one call: palette AND structure AND ground.set_palettealone re-themes only colour (a baredeckkit.MAGENTA = …does not re-theme components whose signature default binds at import);deckkit.set_geometry(radius=…, rule_w=…)carries the structural half —radius=0squares every box-based component andnode(), which is how you reachbrutalist/swiss/ink_wash/blueprint, whose own guards forbid rounded cards;rule_wscales every card border, divider and node outline, which is the other half of what makes brutalist look brutalist.deckkit.set_ground(<bg>)is the third token —apply()sets it andadd_slide()paints it, so the 8 dark registers are dark from slide one instead of leaving the author to remember (measured before it existed:dark_techshipping its light ink on a white canvas at 1.18:1). All three are no-ops at their defaults (scripts/presets.py·references/design-by-purpose.md·references/design-gallery.md). Two rules survive no matter what: never ship deckkit's default blue, and never reuse the last deck's scheme — each deck gets its own distinct identity. Both are now GATED against the render rather than left to memory:scripts/check_register_pixels.py(run by--gate-checkas theregister_pixelssection, and by the codex gate) measures the deck's own PNGs and fails when deckkit's stock identity is what actually shipped, when a declared colour reached no pixel, or when the canvas repeats a recent deck's fromtaste.md's LOOK HISTORY. It is the only check that can see a bespoke register at all —check_style_applied.pyreads the build script for apresets.apply()call, which a hand-built register does not contain. 🔴 It judges COLOUR only. The shape-level half isscripts/check_register_guard.py(--gate-checksectionregister_guard, and the codex gate): each preset's ownguardstates what its register FORBIDS, andpresets.FORBIDScarries the part a machine can settle — rounded corners underswiss/brutalist, gradients underrisograph/bauhaus, an unswitched theme shadow, a proportional face underterminal, more than one oversized primitive underbauhaus. 🔴 Only 7 of 18 registers declare prohibitions and that is deliberate: "photography carries ALL the colour" and "titles must be full-sentence conclusions" are equally real and undecidable from the file, so they stay prose and the checker REPORTS which registers it could not check.apply()sets palette, geometry tokens and ground — nothing more. Measured: one page through all 18 presets produced 18 pages differing only in ground, radius and rule weight, with none of memphis's header bands or bauhaus's primitives. The register'ssurfacefield is the executable spec; read it and BUILD it, or the deck is a palette wearing a name. Composition still needs a render and your eyes. And on a printed surface it inverts: freshness there must come from paper warmth, accent hue and type — never from going dark, which is the one ground print shops uniformly advise against. -
🔴
apply()gives you the register's COLOURWAY;register_surface.pybuilds its SURFACE. Measured by rendering it: one identical page through all 18 presets produced 18 pages differing only in ground, ink, accent, one font swap and a line weight — no memphis bands, no bauhaus primitive, no glass, no overprint, no scanlines, becauseapply()calls exactlyset_palette/set_geometry/set_ground/ the font setters and each preset'ssurfacefield is prose for an author to build by hand, which meant it was never built.register_surface.ground(slide, "<register>", role=…, index=n)paints that register's own furniture and returns the content rect left over (liketitle_bar()returns its content top — nothing loud is painted into it, and a kit that breaks that RAISES);register_surface.card(slide, "<register>", x, y, w, h)gives its card FORM, which is what stops the pages differing only in colour: a memphis banded card, a bauhaus hard square, a riso sticker with an offset plate, a glass panel, a terminal output block. The marks (halftone·starburst·boomerang·zigzag·tri·scanlines·color_band) are callable on their own, so a BESPOKE register can borrow one. 🔴 All 18 registers have a kit —--listprints each one beside thesurfaceline it was built from,--sample <out.pptx>renders one page per register with identical content so the difference IS the register, and a name that is not a register RAISES rather than quietly handing back a plain page (as does painting a surface beforepresets.apply()has set the palette). Both--gate-checkand the codex gate NOTE a deck that declared a kitted register and used none of it: a deliberate quiet treatment is a real choice, forgetting the kit exists is not. -
🔴 A kit scales, and a kit may not INVENT. Kits compose in REFERENCE inches on a 10 x 5.63in canvas and scale to whatever canvas they are handed, so the same furniture keeps its proportion on the 13.33in variant, on portrait 9:16, and on the A0/A1 posters
formats.pysupports — inches do not travel, and a fixed 0.42in mark measured 4.2% of one canvas's width and 1.3% of another's before the scale layer existed (bauhaus also RAISED on portrait, because amax()floor on the leftover band pushed the rect back over the hero it was protecting). And furniture may state the page's own facts and nothing else: an early version printed an invented masthead brand, a fabricated revision letter and a made-up year badge on every page that used them — the never-invent rule broken by the CHROME rather than by the content. A test now holds the entire vocabulary a ground is allowed to say, and another holds its chrome to the 3:1 text-contrast floor on its own ground (dk.MUTEis tuned for a LIGHT canvas: used flat it measured 2.85:1 on blueprint's navy — resolve it withmute_for(GROUND)). -
🔴 An INVENTED register can be a kit too — it is not limited to components and a palette.
register_surface.register(name, ground=…, card=…, forbids=…)gives a bespoke look the same standing the 18 presets have:ground()/card()work, the loud-mark invariant holds, the furniture scales to any canvas, the ink resolves from the ground, andcheck_register_guardenforces the prohibitions the register DECLARES — what a register refuses to do is what separates it from a colourway.python3 scripts/register_surface.py --new "<name>"scaffolds one with every contract already wired (fill inground()andcard(), then run the file: it renders its own three-page preview). Before this, a bespoke register's look was hand-built in the deck'sstyle.pyand NONE of those contracts reached it, andreferences/bespoke-registers.md's four worked examples were prose — zero lines of runnable code. Those four now ship asscripts/bespoke_kits.py(current·transit-signage·ledger·k-space):import bespoke_kitsregisters them,--samplerenders them. They are STARTING POINTS for their family, not looks to paste.save_register.pyrecords the kit file beside the register at hand-off, so the next deck on that subject starts from the built look instead of from a description. -
🔴 A deck's own kit lives BESIDE the deck, as
surface_*.py, and every gate loads it from there. Registration happens at import time and the gates run in a fresh process after the build, so before this a bespoke register's declared prohibitions were enforced in-process and NOWHERE ELSE — measured with a scaffolded kit forbidding gradients and a deck drawing one: caught in a test, and reported by the real gate as "a bespoke look has no FORBIDS to check".register_surface.load_kits(<deck dir>)is called bycheck_register_guardon both runtimes; a kit that fails to import produces a NOTE saying its register is unregistered, never a silent "nothing to check". Both--gate-checkand the codex gate also say, at hand-off, whether an invented register HAS a kit — without one its look is hand-built and none of the contracts (content rect, loud-mark invariant, canvas scaling, ground-resolved ink, its own prohibitions) reach it. Put the file in the deck folder:--new "<name>" --out <deck-dir>/surface_<name>.py. -
🔴 The direction the user PICKED is checked against the deck that SHIPS. The branch-(c) gate renders four directions and records the pick as a sentence; nothing compared that sentence to the built file. Measured on a delivered deck: the chosen direction declared a Georgia display face and a centred cover, and the deck shipped Helvetica Neue titles and a low-left cover —
style.pysetdisplay=and every title passeddk.FONT, so the DISPLAY slot was never read. The author caught it; no gate could, whilecheck_register_pixels(a declared colour must reach the pixels) andcheck_style_applied(a declared preset must be called) had covered the identical class for a long time.check_direction_applied.pycompares ground, accent presence, display and body faces, andcentredvslow-left— and names skeleton and motif as NOT CHECKED rather than guessing at a judgement. A deviation is normal design and is recorded per axis (design_plan.direction_deviations): a freshness gate moves a ground, a contrast floor moves an accent. An unrecorded one is the version the user cannot see. 🔴 And a direction'scover_motif/ambient_motifmust DRAW, not describe — they are raw HTML and the preview renders them, so a sentence lands as literal text on all four sample tiles and the author picks a direction covered in the author's own notes;directions_diversity.pyreports prose in a drawing slot, and the description belongs innote, which the preview already shows. -
🔴 An invented register is KEPT at hand-off, or it is gone when the folder is.
python3 scripts/save_register.py <deck-dir>appends it to<registry root>/registers.mdbesidetaste.md— nothing is re-described, it reads the pick, palette, signature move andmotif_generatesalready in.deck-gates.jsonand adds the colours that reached the pixels. Measured before it existed: the example library held 4 invented registers while one user's look history held 9 that had shipped and been lost, because the mechanism was "remember to edit the markdown".--from-historyrecovers what a look history already names;--listshows the collection. Read it at Step 2 alongside the preset gallery — not to reuse a look (freshness still forbids that) but because a register that already made an argument about X visible is the best start for the next X. -
Accessibility is a FLOOR, not a nicety.
lint_deck.A11Y_CODES— missing alt-text, untitled or duplicate-titled slides, reading order, non-text contrast — is held by--gate-check'sa11ysection and by the codex gate from one shared list, because a floor kept in two places is how one runtime quietly stops enforcing it. 🔴 Decodability is now MEASURED, not asserted. Three checks, each turning a rule this skill already stated into something countable, all added after a first human reader asked three questions of a deck that had passed every gate:MOTIF_UNEXPLAINED_AT_FIRST_USE— the stranger test is about FIRST appearance, and the old check cleared on a legend anywhere, which is the deferred reading SKILL.md calls "a FAILED test written as a passing sentence";UNNAMED_REPEATED_MARK— four or more identical marks with no text within reach are reported, because unlabelled repetition reads as texture whatever you meant by it, and such a group is invisible to every other check (not text, not tagged, trivially clears contrast); and the icon waiver's category is verified against the built file —motif-dominantneeds a real loud motif,tiny-decka real tiny deck,template-lockeda real template, and the waiver must name EVERY flagged slide, not a subset. Only the unambiguous subset blocks (lint_deck.A11Y_BLOCKING): a shape either carries a description or it does not, two slides either share a title or they do not, a ratio either clears 3:1 or it does not.NO SLIDE TITLEstays advisory on purpose — lint's own message calls an off-canvas title "a sanctioned trick for statement slides", so the skill EXPECTS slides that look untitled, and measured on an ordinary well-built 11-slide deck it fired once, on the closing slide. A gate that fires on a deck built exactly to spec is not a floor; it is training for the waiver reflex. Waive in writing ({"a11y": {"waived": "<who reads this deck, and how>", "waived_category": "…"}}) and say so in the hand-off note.scripts/palette_audit.pynow also simulates deuteranopia/protanopia/tritanopia and names any pair that stops being two colours —dk.OKABE_ITOwas recommended for years with nothing checking it.
Fonts (every deck, both branches). A .pptx stores font names, not the fonts — before setting deckkit.FONT/MONO/EAFONT/EQ_MATHFONT, read references/deck-setup.md → "Fonts" (CJK EAFONT is required for any Chinese / Japanese / Korean deck; portability, the EQ_MATHFONT / STIX / Cambria Math dependency to flag at hand-off, and tofu recovery live there) and flag any font dependency at hand-off.
🔴 A face the deck NAMES but the machine cannot RESOLVE is a measurement fault, not a portability note. Every fit/wrap/overflow/footer guard sits on deckkit._measure_lines, which measures whichever face it can resolve — so a named-but-absent face makes the build and the lint compute from the same wrong number and agree with each other while the render disagrees with both. "Will the presenter have it?" stays advisory (unknowable from the file); "does it resolve HERE?" is decidable and now blocks at hand-off on both gate paths via scripts/check_fonts_resolve.py (waive with {"fonts": {"waived": "<why a substituted measurement is acceptable here>"}}). Two consequences worth knowing before you set a face: deckkit's shipped defaults are FONT='Calibri' / MONO='Consolas' and neither ships with macOS, so a stock macOS build measures everything in a stand-in until you call deckkit.use_platform_fonts() or install them; and a font that lives only inside an application bundle (macOS keeps Calibri and Cambria inside PowerPoint) is invisible to the renderer, so copy it into ~/Library/Fonts first — ask before copying, it is the user's machine.
Step 4 — Build with deckkit
🔴 Step 4 opens with the ANCHOR PROOF — THREE slides, rendered, BEFORE the other slides exist
🔴 AND THE SIGNATURE ANCHOR IS COMPETED, NOT COMPOSED ONCE. Build 2–3 genuinely different compositions of that one page, render them in ONE pass, read them blind, and pick by what you SAW. Why here and nowhere else: this skill compares LOOKS at deck level (the direction gate, 4 rendered directions) and has never compared COMPOSITIONS at page level —
check_direction_applied.pysays so itself, naming skeleton and motif as NOT CHECKED because they are a judgement. This is the judgement, made the way a designer makes it.python3 scripts/render_deck.py <probe>.pptx render # all variants, ONE pass python3 scripts/composition_probe.py compare <probe>.pptx --slides 1,2,3 python3 scripts/blind_read.py packet <probe-dir> # then an independent reader🔴 The pick is made by LOOKING, not by reasoning about the plan. The blind reader answers the same fixed questions on each variant; the one to keep is the one whose
claimcomes closest to the takeaway this page owes — that isblind_read.overlap(claim, takeaway), an actual number, calibrated — with fewestunreadableentries and fewest hard problems. Ties go to your judgement, written down. Deciding from the build script instead is the habit this step replaces.It costs almost nothing: LibreOffice startup dominates a render, so three variants in one pass cost what one costs (measured: 1 page 5.0s, 3 pages 4.5s). Vary the SKELETON, not the colours — how many blocks, which one dominates, does the page run across or down. A recoloured or retyped copy is a look change, the direction gate already owns look, and
composition_probe.pyrefuses it: its divergence measure was fitted on a 10-layout corpus and validated on 9 layouts it never saw (0 errors in 36 pairs), so "three variants" cannot be three restylings. Record it asdesign_plan.composition— the measured signatures, the pick, andwhy: what you SAW, naming the versions you compared.looks betteris the sentence this whole step exists to replace. Aboldness: conservativedeck is not asked (it declared no aesthetic risk); a provided template claimstemplate-locked. 🔴 Every carve is checked AGAINST THE BUILT FILE, not accepted as a word — and a generated visual identity (Q1 d) sits on a blank deck, so it cannot borrow it: the Q1 choice decides the LOOK SOURCE, never who composes the pages. Theboldness:/signature move:contract is approved as prose. The pixels that either honour it or sand it back to safe do not appear until Step 5, after the whole deck is built — at which point the critic's "the signature move got sanded" finding costs a rebuild, and that cost is exactly why it gets accepted instead of fixed. Put the evidence where the decision is — and prove the three things that each cost a rebuild when they surface at Step 5, not just the one:
anchor the page what it proves the failure it catches signaturethe slide signature move:namesthe aesthetic risk survived the build the move got sanded back to the safe catalogue complexthe densest page in the content plan the design HOLDS the content looks good but cannot hold the content — a look approved on a spacious page datathe most critical data/conclusion page the charts speak the same visual language palette + type were chosen against text, and the first native chart obeys none of them (Why not the cover, the obvious third? It already has two gates — branch (c) renders four full directions at the direction gate, branch (d) posts a rendered hero at its own 🔴 checkpoint. Making it an anchor would re-prove the one page nothing was missing on, and leave these two unproven.)
- Author the three anchor slides first — the signature slide plus its
carried_by:partner if the idea's structural claim is only legible across the pair, the densest planned page, and the key data/conclusion page. On a deck with fewer than three slides the count drops to the deck size (a 1–2 slide tiny-ask skips the ritual entirely, below).- Build, then render just those pages:
python3 scripts/render_deck.py <deck>.pptx <out> --slides N,M,K. The PNGs are byte-identical to the same pages from a full render, so they are evidence, not an approximation. 🔴--slidesis not the saving here — three pages cost about what all eighteen cost (below), because the render is a fixed LibreOffice start. What this ritual saves is AUTHORING: you learn the design is wrong having built three slides instead of twenty.- Post the three PNGs with one line each: "this is what
<signature move>actually looks like" · "this is the design carrying the heaviest page" · "this is a real chart in this language." A 🔴 stop in the default flow; under a per-deck AUTO WAIVER it downgrades to a posted FYI like every other approval stop — the waiver removes the wait, never the artifact.- Then author the rest. If the proof is wrong you have re-authored THREE slides, not twenty.
- Record it — the run carries a
signature proof:token to Step 5 on the critic contract card, one entry per anchor:signature proof: signature slide N → <png> · complex slide M → <png> · data slide K → <png>orskipped: <the named carve>. Without it the step is advisory by construction, which is the failure mode this whole batch exists to fix: the critic can then check each SHIPPED anchor against the frame that was approved, and a silent skip is visible instead of invisible. The delivery gates enforce the same three (design_plan.signature_proofis now a LIST of{role, slide, png}— one contract inscripts/anchor_proof.py, imported by both gate paths so they cannot drift apart).🔴 The carve is now RECORDABLE, which it was not:
{"material_probe": {"waived": "<which template / which mimic / how many slides>", "waived_category": "registered-template | provided-template | mode-a-mimic | tiny-ask"}}. Both gate paths accept it and both refuseconservativeas a category, because this block says restraint is a material decision too. Before this the gate had no waiver arm at all, so a deck on a registered template had to invent a probe artifact and write a note explaining that the gate and this text disagreed — a rule whose documented exception cannot be recorded forces a false record. Skip only when:boldness: conservativewith its "deliberately restrained" clause recorded (no risk was taken, so there is nothing to prove), or a 1–2 slide tiny-ask. A registered/provided template does NOT skip it — a borrowed look still has a signature slide, and that is exactly where a template deck either becomes designed or stays a template.(Measured on an 18-slide deck: a
--slidesrender ≈ 2.9s and a FULL render ≈ 2.8s — the same, because both pay one ~2.5s LibreOffice start and page count barely moves it. So the proof is cheap in absolute terms (one build + one render, a few seconds), not because it renders fewer pages; the saving that matters is the twenty slides you did not author yet. Going from one anchor to three is therefore close to free on both axes that cost anything: the render is one fixed start either way (~0s more machine time), and all three pages go in the SAME build script and the SAME render call, so the ROUND-TRIP count — the thing a deck's wall clock is actually made of — does not move. What you spend is authoring two more slides; what you buy is discovering that the design cannot hold your densest page while three slides exist instead of twelve. It costs less than one critic round, and it is spent BEFORE the expensive authoring rather than after. This does not contradict "build the whole deck in one script run" below: the proof runs the SAME build script while it still contains only the three anchors — you extend one script, you never maintain two. Asset note: the signature slide's assets are the first thing asset-prep delivers, per its brief. One render can serve several rituals: when Gate A's one-real-slide fidelity confirm has not yet run, use the signature slide AS that confirm slide; on a large deck the proof doubles as the early-render sample. Never run three separate single-slide ceremonies. If the proof looks WRONG: revise the signature slide in the same build script and re-run the same--slides Ncommand — the loop is slide-level and costs seconds; slide N here is the slide's CURRENT index, so if later authoring renumbers it, thesignature proof:token records the final number at hand-off.)
Write a small per-deck build script that imports scripts/deckkit.py (don't re-derive primitives;
full signatures + behaviour are in its docstrings). Build the approved Design plan (form ledger,
rhythm, per-slide design, colour, logo) as the source of truth — the slide-design agent already chose
each slide's visual FORM and the user approved it at the DESIGN checkpoint, so don't re-derive an
approved form. Fallback only where the plan left something open: pick that slide's form deliberately —
generate 2-3 candidate forms and choose with the tie-breaker in references/form-selection.md;
don't default every multi-item slide to a card grid.
🔴 When a COMPONENT exists for the form, BUILD that component — do NOT hand-roll a substitute from raw
box/connectorprimitives. Reaching for a plotted form (waterfall,gantt,dumbbell_board,dot_strip,tier_stack,native_chart,eval_matrix,heat_matrix,meter_bar,timeline…) and then hand-drawing it with boxes re-introduces the exact geometry & grammar bugs the component already fixed — a baseline width hardcoded to a number that stops short of the last bar (the component derives its axis from the data), a waterfall that double-counts (+8 / +8.3 / +16.3 as peer bars) or conflates two quantity kinds (take-home vs employer cost in one 135% stack). This is the #1 source of "the chart looks messy / wrong" defects. Adapt a component's params or compose from primitives ONLY for a form the library genuinely lacks — and then the burden is on you: derive every axis / baseline / track extent from the data (last_bar_x_end − axis_x, never a hand-picked width), and don't double-count (references/design-principles.md"Designed plots" + "Big numbers"). The helper set, by job:
- Chrome:
title_bar/content_slide,footer,editorial_header(caps eyebrow + title + hairline),part_eyebrow/page_marker(mono eyebrow + page marker),logo(persistent brand/institution/product mark in a fixed corner on every page — see the brand-logo rule below). - Safe layout — measure or anchor, never hand-pick a y:
columns/rows(equal orweights=-proportioned split panels — a measured 1/3–2/3 or rail+main split — symmetric outer margins either way),content_band(the SAFE rect below title / above footer),bottom_callout(footer-safe bottom takeaway — anchors to the band, grows UP, can't collide),vstack(…, bottom=)(measured stack: equal gaps + no overlap by construction, errors at build time on overflow) with themeasure_callout/measure_bullets/measure_texthelpers,spaced_centers(evenly-spaced marker centers for a timeline / tick row / numbered steps, inset at the ends so a centered caption stays co-centered with its end marker — use it instead of hand-rolling a row of dots+captions, which desyncs the first/last caption from its dot near a slide edge;timelinealready uses it),picture(fit="contain"keeps edges /"cover"crops),make_gif(GENERATE a looping GIF from computed frames) +gif(embed the animated GIF, undistorted + size/still warnings) +gif_poster(extract the first/representative frame to verify what the render & PDF export show) — generate → embed → review,icon/icon_tile/icon_badge/icon_ghost/icon_card(place an open-licensed SVG icon — recolored + rasterized viascripts/icons.py, which also does duotone weights + gradient-fill;icon_tileis the versatile container — circle/squircle/square × solid/gradient/glass tile,icon_badgea ring badge,icon_ghostan oversized faint watermark,icon_cardthe upper-left feature-card pattern; vary the treatment to fit the deck — seereferences/icons.md"Treatments"). (These exist so you never hardcode a lowy— the recurring overlap/footer bug.) - A shape deckkit has no helper for →
dk.adopt(slide.shapes.add_shape(...)). python-pptx leaves the theme<p:style>on a hand-added shape, so LibreOffice draws a soft drop shadow under it andlint_layoutreportsINHERITED_EFFECT; the only cure used to be the PRIVATE_flat, which an author finds by reading the source.adoptreturns the shape, so it composes inline. - Shape primitives:
box(a rectangle;round=Truerounds its corners) anddisc(a CIRCLE, or an ellipse withh=). 🔴box(round=True)cannot draw a circle at any radius — it is a rounded rectangle andr=d/2is still a rounded rectangle. Measured: a deck whose signature motif was a two-state ring shipped three rendered iterations with a green SQUARE where its device belonged, with no error and no lint code, because the library usedMSO_SHAPE.OVALseventeen times internally and exposed it nowhere.disc(s, x, y, d, fill=…, line=…, line_w=…)takes the same grammar asbox, places from the TOP-LEFT like every other primitive, and is flattened so it carries no inherited theme shadow. - Editorial picture forms:
picture(..., fit="cover", shape="ellipse"|"arch"|"snip"|"notch"|"blob")clips a photo to a circle, an arch, chamfered corners, a notched card or an organic blob (the mask is real in the render, not just the XML);focus=(fx, fy)aims the crop so a face is not cut off;rotation=tilts a pinned print. Both gates measure a rotated shape where it PAINTS — exact at 90°, so a vertical margin label is safe. A cut-out PNG becomes a sticker withimage_fx.sticker_outline(path)(it refuses an opaque photo: cut the subject out first). 🔴 A masked or rotated picture is still a CONTENT image — alt text and the referent rule apply. - Highlighted words:
dk.mark(run, color)puts one run on a highlighter block inside atext()paragraph — native<a:highlight>, follows the wrap, works for CJK. A shape drawn behind the word instead is placed by guesswork and drifts off it when the line wraps.mark()refuses an ink under WCAG on its highlight (pick the ink withdk.on(color)); the render gate reads the highlight as that run's backing. - Hand-made marks (
scripts/ornaments.py):squiggle·scribble·brush_stroke·tape·scallop— native editable geometry, tagged as quiet motif (loud=Truefor a hero), so the motif budget counts them and TEXT_OVER_MOTIF sees a caption laid across one. Use one or two that MEAN something (a squiggle under the claim,tape(..., holds=pic)holding the print —holds=declares that one overlap and refuses a print the tape does not touch), never confetti. A number set on a smallscallopbadge reads as text over a device: declare it withdk.overlap_intent(<the TEXT shape>, "<why>")— the check reads the declaration from the text, not from the badge. - Pure decoration:
dk.decorative(shape, "<why>")declares that nothing a viewer must read rides on a shape — a pale washi tape, a hairline flourish — so the hand-off floor NON-TEXT CONTRAST (WCAG 1.4.11, which exempts decoration) does not hold it. Per shape, with a sentence (CJK counts double toward the floor); the lint PRINTS every exemption with its reason. Undeclared, a mark under 3:1 on the page ground is still held — the check cannot tell ornament from a meaningful mark. - Text & blocks:
bullet,callout(auto-grows),chip,modbox(a labelled MODULE box — reach for it as the node when mapping architecture modules / code files / system parts joined byconnector, where a plainnodeis too bare; role word + optional filename/tag),arrow,table(highlight the key row),code_block,hrule. - Colour:
palette(n, ACCENTS)(n distinct, contrast-checked fills — warns on adjacent same-hue; never a gray filler),palette_from_image(match a generated template's palette),accent_one(one-accent discipline),contrast_ratio(verify ≥~4.5:1 before committing). - Data furniture & charts:
scorecard/leaderboard/takeaway_rail,change_stat(baseline- centred before→after),stat_row,big_numeral; editable native chartsnative_chart/native_dual_axis/native_donut/native_pareto/native_bubble(feed them straight from a spreadsheet withseries_from_csv(path, x_col, y_cols)→(categories, series), stdlib, no pandas), plus the raster recipes inscripts/designed_charts.py(incl.waterfall— a total's rise/fall/ total walk, semantic up/down colour;distribution— the form to use when a value is a mean of MEASUREMENTS rather than a count, since a bar of sample means hides n, shape and outliers;marimekko— size and share at once;radar— a profile across 3–8 axes, ≤3 series) — pick perreferences/data-viz.md. - Page ARCHITECTURE (the skeleton, not the contents):
skeleton(slide, kind)returns the named rects for one of the eight architectureslint_deckalready demands variety across —statement·split·island·dashboard·band·full_bleed·rail·gallery(flip=Truemirrors the asymmetric three). It paints nothing, likecolumns(). 🔴 Decide the SEQUENCE before you build:python3 scripts/plan_rhythm.py --roles <r1,r2,…> --carry <n,m>proposes an architecture per slide from its role, guarantees ≥4 distinct and no repeat inside a 3-slide window, and runs in ~40ms — deterministic arithmetic, not a model call. SKELETON VARIETY and LAYOUT SAMENESS both fire AFTER the build, when varying the architecture means re-laying written pages; measured, the same content planned scored 8 distinct skeletons against 2 improvised. It is a PROPOSAL — deviate where the content wants something else, and record the deviation. Pass--home <skeleton>when a direction gate picked a composition, so the user's pick stays the deck's visible default. At review time,python3 scripts/composition_cues.py <deck-dir>reports seven measured cues and the deck-wide RANGE per cue — a FLAT range is the samey-deck finding no per-page look produces, and it is reported, never gated. - Modular layout:
bento(slide, x, y, w, h, tiles, cols=…)— a grid of UNEQUAL tiles on one rhythm, packed from(span_cols, span_rows)spans and returning rects for you to draw into.columns()/rows()give equal-weight strips andcolumns(weights=…)varies width within ONE row; this varies both axes against a single module, so one message splits into units of honestly different importance — the biggest tile is the point and the reader gets the ranking from the geometry before reading a word. The gutter is one number for the whole grid, because unequal gutters are what make a modular layout read as an accident; it raises rather than silently dropping a tile that will not fit. - Walkthrough / hierarchy / comparison-grid:
image_grid(an N×M LABELLED IMAGE COMPARISON — methods across the columns, cases down the rows, a metric under each cell. THE results slide of an image/reconstruction talk, and the one image idiom where a grid IS the argument, soform-selection.md's "one strong image beats a grid of small ones" does not apply. It reads each picture's REAL placed rect back and derives every label from it, and locks ONE aspect ratio for the whole grid socontainandcovercoincide — zero letterbox, zero crop, by construction. Refuses mixed FOVs, ragged rows, a missingcol_labels, >16 cells, sub-0.8in cells and a metric that wraps, rather than shipping unreadable thumbnails. Measured on the hand-rolled version it replaces: every label 0.67in off the pan
FAQ
What does the slide-maker skill do?
Build, redesign, and critique clean, presentation-grade slide decks (.pptx) for any audience — research/lab meetings, work status updates, conference talks, stakeholder readouts, thesis defenses, teaching, webinars. Use whenever the user wants to make, create, redo, clean up, improve, or review slides / a deck / a presentation — e.g. "make slides for my project", "build a deck from this paper/code/doc", "turn these results into slides", "redesign this pptx", "my slides are too dense", "review my deck and tell me what's weak", "make a slide about X", "help me present this work". Works with or without a template (matches theirs, else designs a clean one) and with or without source material (mines provided code/docs/figures, else web-researches and fact-checks), in any language (e.g. English or Chinese). Interviews first, then runs an actor–critic loop until an independent critic consents. Trigger even without the words "skill", "deck", or "pptx".
How do I install slide-maker?
Run npx skills add https://github.com/addsumtech/slides_maker --skill slide-maker in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/slide-maker/ (personal) or .claude/skills/slide-maker/ (project).
Which AI agents can use slide-maker?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is slide-maker safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains slide-maker?
It is published by addsumtech in addsumtech/slides_maker. It has 1,253 recorded installs.
Popular docs & writing skills
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.
lark-markdown
open.feishu.cn
飞书 Markdown:查看、创建、上传、编辑和比较飞书中的原生 Markdown 文件。当用户要操作飞书 Markdown 文件,或比较其远端版本及本地草稿时使用。纯本地 Markdown 文件操作不触发本 skill。不负责将 Markdown 导入为飞书在线文档,也不负责文件搜索、权限、评论、移动、删除等云空间管理操作。
writing-beats
mattpocock/skills
Writing, exploit; assemble raw material into a journey of beats, grounding each term before a beat leans on it.
writing-shape
mattpocock/skills
Writing, exploit: shape raw material into an article, paragraph by paragraph.
writing-fragments
mattpocock/skills
Writing, explore: mine raw fragments, no structure yet.
writing-for-agents
mattpocock/skills
Writing documents for agents. Use when creating or editing skills, or modifying AGENTS.md or CLAUDE.md.