Seven-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, create and publish talk-content Agent Skills with talk pages to a Jekyll shownotes site, and verify a recorded screencast against its storyboard. Includes a 113-entry Presentation Patterns taxonomy (83 observable: 64 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns) for scoring, brainstorming, and go-live preparation.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
outline.yaml is the source of truth for the talk's content. The schema is
defined in scripts/outline_schema.py (pydantic v2 model); validate any draft
with "{python_path}" "{speaker_toolkit_root}/skills/presentation-creator/scripts/outline_schema.py" outline.yaml. The four derived
artifacts (narrative.md, script.md, slides.md, rhetorical-review.md)
regenerate deterministically — never hand-edit them.
A complete worked example lives at tests/fixtures/outline-example.yaml.
New outlines declare root schema_version: 1. Previously unversioned outlines
remain read-only-compatible; the creator adds the stamp on the next authoring
pass. Explicit unsupported root versions fail closed. This does not rewrite
an existing file during loading.
The outline needs to be:
script: items in the speaker's actual voice (multi-speaker talks attribute every line)visual: / text_overlay: / image_prompt: rich enough to build slides fromcuttable: true on chapters or slides that drop for short slotstalk: blockAuthored in Phase 1; never re-edited carelessly. Field reference (see
outline_schema.py:TalkMetadata for the authoritative list):
| Field | Required | Notes |
|---|---|---|
title | yes | Talk title — appears in extracted artifact headers |
slug | yes | Kebab-case (venue-year-topic) — names the deck file and shownotes path |
speakers | yes | List of speaker names; multi-speaker talks force speaker: on every script line |
duration_min | yes | Slot length in minutes |
audience, mode, venue | yes | Short prose |
audience_spread | yes | heterogeneous (cover all four registers) or homogeneous (match one). Set at intake — see phase0-intake.md Step 0.4 and patterns/prepare/walk-around.md |
dominant_register | conditional | A | B | C | D. Required iff audience_spread: homogeneous; rejected otherwise |
slide_budget | yes | Integer; expanded build count is validated against this |
pacing_rate | yes for new outlines | Complete typed narration rate from owner planning output; see skills/vault-profile/references/speech-rates.md |
pacing_wpm | legacy only | Ordered positive [low, high] integer tuple; an unverified narration assumption retaining internal gaps ≤2 s, never a measurement. Cannot coexist with pacing_rate |
architecture | yes | One of: narrative-arc, sparkline, fourthought, triad, talklet, expansion-joints, lightning-talk, takahashi, cave-painting. Filled in Phase 2 — leave a placeholder at Phase 1 |
engine | yes | pptx | presenterm. Filled in Phase 2 Decision #2 |
deck_theme | yes | Free-string theme/template pointer. Phase 2 Decision #2 |
engine_source | yes | Provenance of the engine choice. Phase 2 Decision #2 |
applied_patterns | optional | Talk-level patterns (e.g., bookends, mentor, anti-sell) |
thesis | optional | Elaborated paragraph; the slide-ready single sentence lives on the call-to-adventure slide via big_idea_text |
tldr | optional | Short distillation of thesis (a couple of paragraphs or a bulleted list); narrative.md renders it verbatim as the TL;DR and never reprints thesis |
shownotes_url_base | optional | e.g., https://speaking.example.com/ — used by Phase 6 |
commercial_intent, profanity_register | optional | Free prose |
must_include, must_avoid | optional | Lists of strings |
catalog_reference | optional | Pointer to sessions-catalog entry |
delivery_count, delivery_date | optional | First delivery = 1; date in ISO YYYY-MM-DD |
For long-form duration planning, use
"{python_path}" "{speaker_toolkit_root}/skills/vault-profile/scripts/speech_rates.py" with intended_metric: narration.
Keep a measured profile's complete rate and provenance when copying it into
talk.pacing_rate. Use an explicit assumption only when no measured profile
exists; a present invalid profile is an owner error, not a fallback trigger.
The reader supports both v1 equal-sample and v2 family-balanced rates. A present
low-confidence v2 profile also requires owner attention, not an assumed default.
Keep v2 mean, conservative-planning rate, historical range and conditional mean
interval separate. A conservative estimate is not proof that a recording fits.
The full contract and command shapes are in
skills/vault-profile/references/speech-rates.md. Recording verification uses
actual complete-recording duration and aligned words, independently of the
planning estimate. Keep timeline, narration, short-phrase, and articulation
values labeled in reports.
chapters: blockAuthored in Phase 2; section-level scaffolding for narrative.md. Each chapter:
- id: ch1 # stable kebab id, referenced by slides[].chapter
title: "Cold Open"
target_min: 6 # rough time allocation; sum is checked against duration
accent: red # optional — visual theme tag (e.g., color code per section)
cuttable: false # set true on sections that drop for short slots
argument_beats:
- text: "Beat as a paragraph. Slide refs natural in the prose."
slide_refs: [1, 2] # validated against slides[].n at load time
tags: [hook] # free-form authoring tagsargument_beats[].text is the prose argument of the narrative arc and the
body of the partial narrative.md (Phases 1–2). Keep it dense and
one-paragraph per beat. Once slides are authored, the full narrative.md
switches to a one-line-per-slide walk and no longer renders the beats. The beats
are Phase 2 scaffolding, not final-artifact copy. The slide_refs field stays a
structured cross-reference: the schema validator rejects any ref that doesn't
match a real slide number in slides[].
slides: and interludes: blocksSlides are the deck-facing units; interludes are between-slide events
(live demos, terminal switches) anchored by after_slide:.
- n: 17 # slide number; unique and ascending; n=0 allowed for title cards
chapter: ch3 # must reference a valid chapter id
title: "Five Pillars"
format: FULL # FULL | IMG+TXT | EXCEPTION | TITLE | DEMO
format_justification: "" # required when format == EXCEPTION
cuttable: false
visual: "Five classical pillars, labeled."
text_overlay: "Five pillars. Most teams have one." # what's literally on screen; "none" for image-only
image_prompt: | # only when style_anchor is set + format != EXCEPTION
[STYLE ANCHOR]. Five classical pillars, all labeled, soft morning light.
builds: # progressive reveals; each step expands to one deck slide
- { step: 0, desc: "Empty frame" }
- { step: 1, desc: "First pillar reveal" }
script: # screenplay form — see Script section below
- cue: "SLIDE 17 UP"
- parenthetical: "(beat)"
- line: "Five pillars. Most teams have one." # single-speaker
- { speaker: "Patrick", line: "..." } # multi-speaker
applied_patterns:
- { id: star-moment, subtype: shocking-statistic }
- { id: walk-around, registers: [C, D] } # which questions this claim answers
callbacks:
- { kind: plant, id: receipt-motif }
- { kind: pay, id: same-model-same-task, variation: "Same model. Same question." }
progressive_lists:
- { id: cheat-sheet, item_index: 2 }
running_gags:
- { id: mod-7, appearance_index: 3 }
placeholders: ["AUTHOR-04", "DATA-02"]
big_idea: true # exactly ONE slide in the talk has this true
thesis: preview # "preview" or "payoff" — preview must come before payoff- id: demo-04
after_slide: 13 # plays between slide 13 and slide 14
chapter: ch-wrong-tool
title: "DEMO 04 — The Wrong Tool (RIGHT)"
cuttable: false
script: [...] # same shape as slide.script
callbacks: [...]
applied_patterns: [...]Interludes have no n, no visual, no image_prompt — they're production
events. They appear in script.md (rehearsal), not in slides.md (deck build).
style_anchor: block (optional)Only present when Phase 2 produced an illustration strategy. Talks without
this block use visual: + text_overlay: only; image_prompt: is omitted.
style_anchor:
model: "imagen-4"
full: |
Full-bleed style anchor paragraph — describes the FULL (1920×1080) format.
imgtxt: |
IMG+TXT style anchor paragraph — describes the portrait (1024×1536) format.
conventions: |
Visual continuity rules (numbering scheme, recurring motifs, annotation style).The [STYLE ANCHOR] token in each slide's image_prompt is replaced by the
illustrations pipeline with the format-appropriate anchor text at generation
time. Slides with no illustration (text-only or EXCEPTION) omit image_prompt.
script: items)A slide's or interlude's script: is a flat list of three item shapes; exactly
one of {cue, parenthetical, line} is set on each:
| Item shape | Meaning | Speaker attribution |
|---|---|---|
{ cue: "..." } | Production direction (slide change, terminal up, build advance) | Never — cues are scene-level |
{ parenthetical: "(beat)" } | Delivery direction (pause, tone, gesture, audience interaction) | Optional in multi-speaker mode; forbidden in single-speaker mode |
{ line: "..." } | Spoken dialogue | Required in multi-speaker; forbidden in single-speaker |
{ speaker: "Name", parenthetical: "(to Baruch)" } | Speaker-attributed stage direction | Common in screenplay form |
{ speaker: "Name", line: "..." } | Multi-speaker dialogue line | The speaker must be in talk.speakers |
Consecutive items with the same speaker: group as one block in script.md.
Floating parentheticals (no speaker) describe the room ("many hands go up");
attributed parentheticals describe a specific speaker's action.
Patterns are declared via applied_patterns: on slides, interludes, or the
talk itself. Pattern IDs come from the closed enum discovered at runtime from
references/patterns/{prepare,build,deliver}/*.md — the filesystem is the source of
truth, and references/patterns/_index.md mirrors it for human readers. Antipatterns
are never declared in
outline.yaml — they surface as detections in rhetorical-review.md.
applied_patterns:
- id: opening-punch
flavors: [personal, unexpected, challenging] # ≥1 from: personal, unexpected, novel, challenging, humorousStrong openings stack 2–3 PUNCH flavors. The first ~10% of the deck must
declare opening-punch with at least one flavor or the rhetorical-review
flags a missing-hook gap.
- n: 17
big_idea: true # exactly one slide in the talk has this
thesis: preview # this slide previews the thesis; a later slide pays it off
applied_patterns:
- id: call-to-adventure
big_idea_text: "Treat context as an engineering artifact."The single-sentence form lives on big_idea_text:. The elaborated thesis
lives on talk.thesis. Preview must come before payoff.
sparkline)# Call to Adventure — turning point 1, 10–25% into the talk
applied_patterns:
- { id: call-to-adventure, big_idea_text: "..." }
# Call to Action — turning point 2, last 15–25%
applied_patterns:
- id: call-to-action
asks:
doer: "specific immediately-executable ask"
supplier: "..."
influencer: "..."
innovator: "..."
# New Bliss — immediately after Call to Action
applied_patterns:
- { id: new-bliss }
# S.T.A.R. moments — at peaks in the persuasive middle (≥1 required for sparkline)
applied_patterns:
- { id: star-moment, subtype: shocking-statistic }
# subtype values: memorable-dramatization | repeatable-sound-bite | evocative-visual
# | emotive-storytelling | shocking-statistic# First telling
- n: 8
applied_patterns:
- { id: master-story, story_id: pandy, beat: introduce }
# Subsequent recalls — each beat: recall-1, recall-2, recall-3
- n: 22
applied_patterns:
- { id: master-story, story_id: pandy, beat: recall-1 }introduce must be the first beat for any story_id; recalls are ordered.
applied_patterns:
- id: inoculation
resistance_vector: politics # one of: comfort-zone | fear | vulnerabilities
# | misunderstanding | obstacles | politicsReserve for objections that would derail the room. The rhetorical-review flags >3 inoculations as a defensive-feeling talk.
# Plant a callback
callbacks:
- { kind: plant, id: receipt-motif }
# Pay it off later
callbacks:
- { kind: pay, id: receipt-motif, variation: "Revealed in full" }Every plant must have at least one pay; every pay must reference a planted id. The schema rejects unpaired ledger entries before the rhetorical-review even runs.
# A list that grows across slides
progressive_lists:
- { id: cheat-sheet, item_index: 1 } # later slides increment item_index
# A gag that escalates across appearances
running_gags:
- { id: mod-7, appearance_index: 1 }Indexes must be contiguous starting at 1. Running gags need ≥2 appearances (otherwise it's a one-shot meme, not a gag).
applied_patterns: on the talk itself for patterns that span the whole talk
(bookends, mentor, anti-sell, delayed-self-introduction,
unifying-visual-theme, master-story, meme-as-argument,
a-la-carte-content, greek-chorus, live-demo, etc.). These don't carry
slide-level instance metadata.
When a slide needs progressive-reveal builds:
- n: 5
format: FULL
visual: "Five pillars, labeled."
image_prompt: |
[STYLE ANCHOR]. Five classical pillars, all labeled.
builds:
- { step: 0, desc: "Empty frame — title and borders only, no pillars" }
- { step: 1, desc: "First pillar (Transparency)" }
- { step: 2, desc: "Add second pillar (Accountability)" }
- { step: 3, desc: "Add third pillar (Fairness)" }
- { step: 4, desc: "Add fourth pillar (Safety)" }
- { step: 5, desc: "All five pillars" }Conventions:
step: 0 is the empty frame (title/borders only, no content)desc is the additive reveal — what the audience sees at that step. It is
human-facing (renders in slides.md) and is what you author hereerase field: the backwards-chaining
edit prompt (with mandatory "Keep …" clauses) that generate-illustrations.py --build sends to the image model. The illustrations skill authors erase
during generation — not content authoring — see
skills/illustrations/references/builds.mdslide_budget (the validator expands max(len(builds), 1))cue: "BUILD 01"Read verbal signatures from the vault summary (recurring phrases section) and
the profile's instrument_catalog.verbal_signatures[]. Place them where they
fit organically in script: items — don't force them.
General placement principles:
profanity_registerdesign_rules.default_bullet_symbolThe specific phrases come from the vault, not from this file.
The first 1–2 minutes of the talk are the highest-stakes real estate. Audiences grant a roughly two-minute "honeymoon period" before forming a verdict on whether the talk is worth their attention. The opening section must contain at least one of five hook flavors, per Reynolds's PUNCH framework:
Strong openings stack 2–3 PUNCH elements. Tag every opening slide that contains
a flavor (see applied_patterns example above). If the opening contains none of
the PUNCH flavors — agenda slide, "let me introduce myself," "thanks for having me"
filler — the rhetorical-review will flag it.
See patterns/prepare/opening-punch.md for the full pattern.
Reynolds: "Contrast is about differences, and we are hardwired to notice differences." When choosing how to frame a chapter or transition, look for the inherent contrast pair:
Contrast structures naturally produce dramatic tension and make the resolution
feel earned. If a chapter feels flat, ask: what is the contrast pair here?
If you can't name one, the chapter is not yet sharpened. (Contrast is rhetorical
guidance, not a tagged pattern — it shapes how you write argument_beats[].text.)
Every placeholder requiring author input MUST use a typed tag — never
generic TODO or TBD. Independent numbering per type (each starts at 01):
| Tag | Use |
|---|---|
AUTHOR-NN | Speaker's specific data or story for this point |
DEMO-NN | Description of what to demo |
DATA-NN | Survey stat needed — describe what's needed |
SCREENSHOT-NN | Description of what to capture (no illustration strategy) |
IMAGE-NN | Real photo/screenshot/data viz needed (for EXCEPTION slides) |
MEME-NN | Meme placeholder — see brief format below |
IMAGE-NN replaces SCREENSHOT-NN in illustration-aware outlines. SCREENSHOT-NN
still works for talks without an illustration strategy.
Placeholders go in the slide's placeholders: list. For memes, include a
structured brief in the surrounding context (free prose in visual: or a
separate notes block):
MEME-01
Template: [meme template name]
Search query: "[search terms to find the template image]"
Overlay text: [specific text to apply]
Rhetorical function: [what argument this meme serves].tessl-plugin
rules
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
screencast-recorder
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile