Six-skill presentation system: ingest talks into a rhetoric vault, run interactive clarification, generate a speaker profile, create presentations that match your documented patterns, produce the deck illustrations + thumbnail visual layer, and publish talk pages to a Jekyll shownotes site. Includes a 102-entry Presentation Patterns taxonomy (91 observable, 11 unobservable go-live items) for scoring, brainstorming, and go-live preparation.
86
92%
Does it follow best practices?
Impact
86%
1.24xAverage score across 26 eval scenarios
Advisory
Suggest reviewing before use
Process steps in order. Do not skip ahead. The phases below are a numbered sequential workflow — Phase 0 must run before Phase 1, Phase 1 before Phase 2, and so on. Late-entry single-task requests (Phase 6 / Phase 7 re-runs) still require the documented pre-flight checklist before any action; do not parallelize and do not bypass the vault-loading or artifact-loading gates.
Build presentations that match the speaker's documented rhetoric and style patterns. The rhetoric-knowledge-vault is this skill's constitution. Every presentation is a joint effort — the skill brings rhetoric knowledge, the author brings topic expertise.
The vault lives at ~/.claude/rhetoric-knowledge-vault/ (may be a symlink to a custom
location). Read tracking-database.json from there to get config.vault_root.
Load from vault root: rhetoric-style-summary.md (constitution — all patterns),
slide-design-spec.md (visual rules), speaker-profile.json (structured data).
The interaction-rules steering rule (one-question-at-a-time, applies to all phases)
is loaded automatically via tile steering — do not treat it as a vault-root document.
Then load local references per phase:
references/phase0-intake.md,
references/phase1-intent.md,
references/phase2-architecture.md,
references/phase3-content.md,
references/phase4-guardrails.md,
references/phase5-slides.md,
references/phase6-publishing.md,
references/phase7-post-event.md,
references/patterns/_index.md.
Checks: Warn if profile.generated_date < summary."Last updated" (stale profile).
Warn if schema_version > 1. If profile doesn't exist (<10 talks), run in
summary-only mode — read instruments from summary prose, use default guardrail
thresholds (1.5 slides/min, 45% Act 1 cap), ask for template/publishing interactively.
| Phase | What happens | Gate |
|---|---|---|
| 0: Intake | Load vault, gather context | Topic and context captured |
| 1: Intent Distillation | Clarifying questions → talk: block of outline.yaml; generate TL;DR-only narrative.md (partial) | Author confirms metadata |
| 2: Rhetorical Architecture | Joint instrument selection → architecture, applied_patterns, chapters[] in outline.yaml; regenerate narrative.md (partial) for review | Author approves narrative + architecture |
| 3: Content Development | Fill slides[] + interludes[] in outline.yaml; finalize narrative.md (full) + generate script.md, slides.md, rhetorical-review.md | Draft delivered |
| 4: Revision & Guardrails | Iterate on feedback, run guardrail checks against outline.yaml | Author declares outline done |
| 5: Slide Generation | Build .pptx from template (or presenterm {slug}.md) using slides.md build-sheet | Author declares slides done |
| 6: Publishing | Export, shownotes, QR per speaker's workflow | Published and ready |
| 7: Post-Event | YouTube thumbnail, video to shownotes | Thumbnail approved, video linked |
Do not skip phases. Do not write content before Phase 3. Phase 2 is joint, not autonomous.
Talk-directory artifacts.
By end of Phase 3, the talk directory contains:
| File | Role | Authored or generated? |
|---|---|---|
outline.yaml | Source of truth — talk metadata, chapters, slides, interludes, patterns, callbacks | Authored (agent-edited, schema-validated) |
narrative.md | TL;DR of the idea + one-line-per-slide deck walk | Generated by extract-narrative.py |
script.md | Screenplay-form rehearsal artifact | Generated by extract-script.py |
slides.md | Per-slide build-sheet (format, visual, image prompts, builds, callbacks) | Generated by extract-slides.py |
rhetorical-review.md | Structural gap-check report | Generated by check-rhetorical.py |
{slug}.md | Renderable deck (presenterm-format talks only) | Authored/built in Phase 5 |
*.pptx | Renderable deck (pptx talks) | Built in Phase 5 |
Regenerate the four derived artifacts after every edit to outline.yaml:
python3 skills/presentation-creator/scripts/extract-narrative.py outline.yaml > narrative.md
python3 skills/presentation-creator/scripts/extract-script.py outline.yaml > script.md
python3 skills/presentation-creator/scripts/extract-slides.py outline.yaml > slides.md
python3 skills/presentation-creator/scripts/check-rhetorical.py outline.yaml > rhetorical-review.mdValidate the YAML with python3 skills/presentation-creator/scripts/outline_schema.py outline.yaml — exits non-zero with a typed error if any validator fails.
narrative.md is the exception to "by end of Phase 3" — it is generated earlier
in partial form during Phases 1–2 so the author can review and approve the
narrative before slide content development:
python3 skills/presentation-creator/scripts/extract-narrative.py --partial outline.yaml > narrative.md--partial validates talk + chapters without requiring slides[]. The
plain (full-validation) commands above apply from Phase 3 onward, once slides[]
exists.
Late entry (single-task requests).
Even when the user asks for a single task (QR code, export, shownotes), vault loading is mandatory. Do not jump straight to the action. Minimum context before ANY Phase 6 action:
speaker-profile.json — publishing config, shortener, URL patternssecrets.json — API keys for shorteners and Geminioutline.yaml — source of truth for talk slug, metadata, slides, and shownotes URL.
Read it via skills/presentation-creator/scripts/outline_schema.py (the pydantic model exposes talk.slug,
talk.title, talk.shownotes_url_base, etc.) — never re-parse the YAML by hand.If the file is missing or fails to validate, STOP and ask. Do not guess values that should come from files. Never hand-write code when a script exists — if the script isn't working, diagnose why (wrong args, missing config, missing secrets) and fix the inputs.
Phase 7 late entry requires the same files plus a YouTube video URL from the speaker. If shownotes don't exist and Step 7.2 is requested, STOP and ask — either run Phase 6 Step 6.1 first or get the shownotes URL manually.
Ask about what's missing; skip what's known. See references/phase1-intent.md for the full
question set. Author the talk metadata block of outline.yaml:
talk:
title: "Working Title"
slug: "venue-year-topic" # kebab-case; names the deck file + shownotes path
speakers: ["Speaker Name"] # multi-speaker talks list every speaker here
duration_min: 50
audience: "who, in one sentence"
mode: "from profile presentation_modes"
venue: "Conference Year, City"
slide_budget: 75 # from profile guardrail_sources.slide_budgets
pacing_wpm: [135, 145] # from profile rhetoric_defaults
architecture: "narrative-arc" # filled in Phase 2 — leave a placeholder
thesis: |
Elaborated thesis paragraph(s). The single-sentence form goes on the
call-to-adventure slide via `big_idea_text` in Phase 3.
tldr: |
A short distillation of `thesis` for the narrative.md reader — a couple
of paragraphs or a short bulleted list. Summarize the thesis; do not
reprint it. narrative.md renders this verbatim as its TL;DR.
shownotes_url_base: "https://speaking.example.com/"
commercial_intent: "none | subtle | direct"
profanity_register: "verbal-only by default; never on slides"
must_include: []
must_avoid: []
catalog_reference: "sessions-catalog.md#entry-id" # if applicable
delivery_count: 1 # 1 for first delivery, 2+ for repeats
delivery_date: "YYYY-MM-DD" # ISO date the talk is/was deliveredGenerate the slug per publishing_process.shownotes.slug_convention in the profile.
Slug validation is kebab-case (lowercase alphanumeric + single hyphens).
Gate: Author confirms or edits the metadata.
Save the partial outline to: {presentations-dir}/{conference}/{year}/{talk-slug}/outline.yaml
Then generate the narrative stub so the author can read the TL;DR early:
python3 skills/presentation-creator/scripts/extract-narrative.py --partial outline.yaml > narrative.mdAt this phase narrative.md carries the TL;DR only — the chapter body fills in
at Phase 2 and the per-slide walk replaces it once slides exist in Phase 3.
Surface it to the author for an early read. Proceed immediately to Phase 2.
The talk block is the source of truth for the slug, duration, mode, and other
metadata. Later phases (Phase 2 architecture, Phase 3 slides, Phase 6 publishing)
extend the SAME file with chapters[], slides[], interludes[], etc. — do not
create a separate spec or outline file.
The instrument menu comes from the vault, not from a static file. Read the summary
(sections 2-13) and profile instrument_catalog for options.
11 decisions to make together:
Mode, Opening, Narrative, Humor, Audience Interaction, Closing, Slide Design,
Persuasion, Template Patterns, Pattern Strategy, Illustration Strategy. Each reads
from the matching instrument_catalog entry + summary section. Decision #10 uses the
4-tier Pattern Strategy from references/patterns/_index.md + profile → pattern_profile.
Decision #11 (Illustration Strategy) is optional — only when the author wants
AI-generated illustrations. Delegate to Skill(skill: "illustrations") for the full
collaboration (style proposals grounded in vault visual_style_history, format
vocabulary, model choice, visual continuity devices). The skill writes the approved
STYLE ANCHOR block back into the outline header.
For each: present options, recommend based on spec, let author choose. If co-presented, add role split and voice differentiation — see references/phase1-intent.md.
Once the architecture is set, author chapters[] (section headings, target_min,
argument_beats[]) into outline.yaml, then regenerate the narrative — now with
its chapter body — for human review:
python3 skills/presentation-creator/scripts/extract-narrative.py --partial outline.yaml > narrative.mdPresent narrative.md to the author. This is the narrative-approval point: the
author reads the TL;DR and the chapter arc and approves or revises the argument
before any per-slide content is written in Phase 3. Leave argument_beats[].slide_refs
empty here — slides do not exist yet, so --partial validation rejects any ref;
wire them to real slides in Phase 3.
Slide budget — read from profile → guardrail_sources.slide_budgets at runtime.
If the profile is unavailable (summary-only mode), use these defaults:
| Duration | Max slides | Slides/min |
|---|---|---|
| 20 min | 30 | 1.5 |
| 30 min | 45 | 1.5 |
| 45 min | 70 | 1.5 |
| 60 min | 90 | 1.5 |
| 75 min | 110 | 1.5 |
Gate: Author approves the narrative (narrative.md) and the architecture.
Fill slides[] and interludes[] in outline.yaml. See
references/phase3-content.md for the full schema,
field-by-field guidance, pattern application, callback ledger, voice calibration,
and placeholder types.
Outline structure (abbreviated YAML):
talk: { … } # from Phase 1
chapters: # from Phase 2 — section headings + target_min
- { id: ch1, title: "Cold Open", target_min: 3, accent: red, argument_beats: [...] }
- { id: ch2, title: "...", target_min: 7, ... }
style_anchor: # ONLY when illustration strategy is defined (Phase 2)
model: "model-name"
full: |
[anchor paragraph for FULL slides]
imgtxt: |
[anchor paragraph for IMG+TXT slides]
conventions: "..."
slides:
- n: 0
chapter: ch1
title: "Title Card"
format: TITLE
text_overlay: |
Talk Title
Speaker Name — Venue
- n: 1
chapter: ch1
title: "Opening Hook"
format: FULL # FULL | IMG+TXT | EXCEPTION | TITLE | DEMO
visual: "what's on screen"
text_overlay: "the literal text rendered on the slide, or 'none'"
image_prompt: | # only when style_anchor is set + format != EXCEPTION
[STYLE ANCHOR]. The generation prompt for this slide.
builds: # progressive reveals — each build is a separate deck slide
- { step: 0, desc: "empty frame" }
- { step: 1, desc: "first reveal" }
script: # screenplay form — what the speaker(s) say
- cue: "SLIDE 1 UP"
- parenthetical: "(beat)"
- line: "Opening line." # single-speaker: no speaker field
- { speaker: "Name", line: "..." } # multi-speaker: every line attributed
applied_patterns:
- { id: opening-punch, flavors: [personal, unexpected] }
callbacks:
- { kind: plant, id: receipt-motif }
placeholders: ["AUTHOR-01"]
big_idea: false # exactly ONE slide in the talk has true
thesis: null # "preview" or "payoff" on the slides where the thesis lands
interludes: # production interludes between slides — usually live demos
- id: demo-01
after_slide: 0 # plays between slide 0 and slide 1
chapter: ch1
title: "DEMO 01 — Live Terminal"
script: [...]
callbacks: [...]When an illustration strategy is defined, every non-EXCEPTION slide carries an
image_prompt. The [STYLE ANCHOR] token in the prompt references the header
anchor — the illustrations pipeline substitutes the actual anchor text at
generation time. Talks without style_anchor use visual: + text_overlay: only.
Placeholders — use typed, independent numbering (each type starts at 01):
AUTHOR-01, DEMO-01, DATA-01, SCREENSHOT-01, IMAGE-01, MEME-01.
Every placeholder requiring author input MUST use one of these typed tags —
never use generic TODO or TBD. See
references/phase3-content.md for full
placeholder definitions and meme-brief format.
After saving outline.yaml, validate and regenerate the derived artifacts:
python3 skills/presentation-creator/scripts/outline_schema.py outline.yaml # validates; non-zero on error
python3 skills/presentation-creator/scripts/extract-narrative.py outline.yaml > narrative.md
python3 skills/presentation-creator/scripts/extract-script.py outline.yaml > script.md
python3 skills/presentation-creator/scripts/extract-slides.py outline.yaml > slides.md
python3 skills/presentation-creator/scripts/check-rhetorical.py outline.yaml > rhetorical-review.mdThe four .md files are read-only — never edit them directly; they regenerate
deterministically from outline.yaml.
Run two checkers — they cover different surfaces:
python3 skills/presentation-creator/scripts/check-rhetorical.py outline.yaml > rhetorical-review.md
python3 skills/presentation-creator/scripts/guardrail-check.py outline.yaml path/to/speaker-profile.jsoncheck-rhetorical.py enforces the closed pattern taxonomy (opening PUNCH,
big-idea singleton, thesis preview/payoff ordering, sparkline structural
elements when applicable, master-story threading, callback ledger, inoculation
count, progressive-list contiguity, duration accounting). Output is the
rhetorical-review.md artifact — PASS / FLAG / N/A per check.
guardrail-check.py enforces speaker-profile-aware rules that depend on
runtime profile data — currently: slide budget, Act 1 ratio limits, branding,
profanity register, data attribution, closing completeness, cut-line
availability (conditional on modular_design). Anti-pattern frequency and
illustration coverage are not yet wired into the script — those still live
in phase4-guardrails.md as additional manual checks the agent should
surface alongside the script's output. See
references/phase4-guardrails.md for the
full check list and report format.
The script currently reports the 7 automated checks; the agent adds the remaining categories manually:
GUARDRAIL CHECK — {talk title}
================================================
[PASS/FAIL] Slide budget: {actual}/{max} for {duration}-min slot
[PASS/WARN/FAIL] Act 1 ratio: {%} (limit: {max}% — WARN within 5%)
[PASS/WARN] Branding: footer elements for {conference}
[PASS/WARN/FAIL] Profanity: {register} applied, {N} on-slide
[PASS/FAIL] Data attribution: {N} slides with numeric claims and source check
[PASS/FAIL] Closing: summary={y/n} CTA={y/n} social={y/n}
[PASS/FAIL] Cut lines: {cuttable_min} min of cuttable content (or PASS-skipped when modular_design is disabled)
================================================Agent-added (not in script yet):
profile.pattern_profile.antipattern_frequencyprofile.guardrail_sources.recurring_issues[] — the script does not run these checks; the agent reads each entry and applies the guardrail field's check manuallystyle_anchor is presentIterate on author feedback. Apply changes first, guardrail second. Flag but don't block intentionally overridden guardrails. See references/phase4-guardrails.md for iteration protocol.
Build the deck from the finalized outline.yaml, using slides.md (the build-sheet
extracted by extract-slides.py) as the per-slide instruction list. See
references/phase5-slides.md for the full technical
reference.
For pptx talks (template-driven):
Emit a deck op sequence from slides.md + the profile layout map, validate it,
then build the deck with the real PowerPoint app — BuildDeck strips the
template's demo slides and creates every slide from the ops. See
references/deckops-spec.md.
python3 scripts/validate-deckops.py ops.txt
scripts/build-deck.sh "{template_copy_pptx_path}" "{output_path}" ops.txtFor non-illustrated slides and EXCEPTION-format slides, emit the content inline
(the IMAGE-NN placeholder resolves to a real asset → an IMAGE op). For FULL
and IMG+TXT slides, emit only the slide structure (layout, TITLE, FOOTER)
and omit the IMAGE op — the slide is left without a picture shape. The
illustrations skill handles illustrations in the post-build apply pass: FULL
slides get a slide BACKGROUND FILL (set by the PowerPoint apply-backgrounds.sh
pass, so the layout's halftone-dot overlay covers them); IMG+TXT slides get a
left-column picture shape via apply-illustrations-to-deck.py.
After the build completes, if outline.yaml declares style_anchor, delegate
to Skill(skill: "illustrations") to generate illustrations, generate any
progressive-reveal builds, and apply them to the deck. The illustrations skill
still expects markdown-style inputs (style anchor block + per-slide image
prompts) — when invoked, surface the relevant fields from outline.yaml in the
format the illustrations skill consumes. Updating the illustrations skill to
consume outline.yaml natively is tracked separately.
Inject speaker notes from script.md after the illustrations skill returns,
via real PowerPoint — skills/presentation-creator/scripts/inject-notes.sh
(notes JSON is the historical {"<0-based slide #>": "text"} map). PowerPoint
writes valid notes OOXML, so the <p:notesMasterIdLst> Keynote patch the old
python path needed is gone. THEN, as the final write, set the FULL-slide
backgrounds via skills/presentation-creator/scripts/apply-backgrounds.sh
using the manifest from the apply pass — it must run last, since any later
python-pptx save would re-drop the per-slide background fills. See
rules/deck-editing-rules.md.
For presenterm talks (terminal markdown):
Hand-author the renderable deck as {slug}.md (e.g., devoxx-uk-2026-300-tokens.md)
using the slides.md build-sheet as input. Each slide's text_overlay: becomes
the slide body; the slide's script: becomes the speaker_note: | HTML comment.
The slug-named deck travels with the talk dir; slides.md remains the
toolkit-canonical build-sheet.
Key rules from profile:
design_rules.background_color_strategy — how to pick background colorsdesign_rules.footer — pattern, position, font, color adaptationdesign_rules.slide_numbers — typically "never"infrastructure.template_layouts[] — layout index + placeholder mappingRead publishing_process from speaker-profile.json. Each speaker's workflow differs.
If publishing_process is missing or empty, ask the author interactively.
Execute the steps from the profile:
0. Resources — extract and curate resource list from outline (extract-resources.py)
export_method / export_script (see references/phase5-slides.md)publishing_process.shownotes.enabled, use curated resources from Step 6.0qr_code.enabled, generate and insert per profileadditional_steps[] entryGate: Author confirms published and ready to deliver.
Triggered separately — days or weeks after delivery. Not part of the linear Phase 0-6 flow. The talk has been given and recorded.
Skill(skill: "illustrations") (the
skill handles slide selection, speaker-photo resolution, aesthetic precedence,
composition via Gemini, and speaker iteration).Read references/phase7-post-event.md for
the pre-flight checklist and Step 7.2 (Video to Shownotes). Step 7.1 detail
lives in skills/illustrations/references/thumbnails.md.
{vault_root}/analyses/skills/presentation-creator/scripts/run-deck-ops.sh. python-pptx editing is
not used — it strips per-slide background fills, flattening illustrated decks.
See rules/deck-editing-rules.md (macOS + Microsoft PowerPoint only). On first
use, walk the user through references/deck-editing-setup.md (enable macros,
import the macro, grant Automation consent) before invoking the script.The sessions catalog ({vault_root}/sessions-catalog.md) is the single source of
submission-ready materials for active talks. Load it during Phase 0 to know the active
rotation and flag overlapping territory. Pull an existing entry before starting a new
CFP; adapt rather than rewrite.
What goes in the catalog.
Each entry contains:
Catalog maintenance.
ai-anti-patterns.md if installed). Keep the "Last updated" date current.--- horizontal rules for easy scanning..github
eval-resources
humor-postmortem-blind-spots
qr-bitly-slug-from-outline
qr-missing-shortener-detection
shownotes-publisher-omit-placeholder
shownotes-publisher-publish-no-date
shownotes-publisher-publish-with-date
shownotes-publisher-update-add-video
video-extraction-diagnostics
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
rules
scripts
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
vault-profile
tests