Eleven skills for conference speakers covering rhetoric analysis, talk authoring, deck building and export, CFP submissions, publishing, illustrations, shownotes, and screencast production, informed by a 113-entry Presentation Patterns taxonomy (83 observable: 64 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns).
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Reference for Step 13 (thumbnail) in SKILL.md. The
thumbnail-generation-rules steering rule is auto-loaded — apply it, don't
restate it.
A shownotes-publisher generation handoff supplies thumbnail_scope: source_only.
Run the read-only preflight and Sub-steps 1–8, retaining their speaker-selection
and approval gates. Return the approved source's actual absolute path as
thumbnail_source to the caller. Do not invoke shownotes-publisher or run
Sub-steps 9–10 in this scope; the caller already owns placement and publication.
It needs no YouTube URL and may run before delivery.
Other thumbnail requests retain the full workflow below. On return from an
authorized shownotes handoff, reuse any approved thumbnail_source it returns
and continue at Sub-step 9 instead of generating the image twice.
Before any thumbnail work, confirm the inputs:
speaker-profile.json — publishing_process.thumbnail config and
visual_style_history.outline.yaml — talk slug, metadata, and slide references; the
style_anchor block (if present) feeds --portrait-style.source_only.config.python_path for the
mutation in Sub-step 10. Missing or invalid config stops this flow and invokes
Skill(skill: "vault-ingress") at Step 1.Set host_python to the current host's explicit absolute interpreter path (not
a PATH lookup). The sole interpreter-bootstrap exception is one stdlib-only
owner read:
"{host_python}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/read-tracking-database.py" \
"~/.claude/rhetoric-knowledge-vault/tracking-database.json"Resolve vault_root and python_path from that report, then immediately repeat
the read with "{python_path}" against the resolved database and require the
same database bytes/SHA-256. The unconfigured host_python is authorized only for the first
owner-reader invocation. Every command below uses the configured interpreter;
never fall back to a PATH interpreter.
Read tracking-database.json through the vault path used by
presentation-creator. Selection and composition may read the generations in the
owner compatibility contract
without mutation. Before placing the approved thumbnail or writing tracking
state, require the owner-current database, current independent records, and talk
schema 8. Invoke Skill(skill: "vault-ingress") for legacy generations and stop
this run. Unknown future generations are no usable prior state. Preserve every
schema field and use the presentation-creator exact-generation atomic-write
contract.
For the full workflow, if shownotes are needed too and don't exist yet, confirm
that page publication is authorized before generating the thumbnail. An already
authorized shownotes request invokes Skill(skill: "shownotes-publisher");
resume here after it returns. The source-only scope returns to its existing
caller instead, as specified above.
Scan the outline for high-impact slides. Suggest 3–5 candidates ranked by visual engagement:
Avoid: bio slides, shownotes URL slides, bullet-heavy slides, generic titles.
Present candidates to the speaker with slide numbers and brief descriptions. The speaker picks one — never auto-select.
Resolution chain:
illustrations/ for
slide-{NN}.* matching the chosen slide."{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
--extract-slide deck.pptx 15 --output slide-15.pngResolution order:
publishing_process.thumbnail.speaker_photo_path from speaker profile.The photo must be a real photograph — never AI-generated. Expression should convey engagement and energy, not a neutral corporate headshot.
NOT the full talk title. A 3–5 word hook designed for thumbnail readability at small sizes.
Walk the precedence chain (thumbnail-generation-rules Rule 7):
publishing_process.thumbnail.aesthetic_preference — explicit speaker
preference ("photo" or "comic_book"). Honor it and stop.visual_style_history.default_illustration_style — fuzzy-match against
the comic-book family (comic_book / comic-book / halftone /
illustrated / cartoon / caricature) → recommend comic_book.
Documented styles outside that set (retro_tech_manual, watercolor,
etc.) → out-of-scope; ask the speaker before generating.visual_style_history.confirmed_visual_intents — same fuzzy-match
against each entry's pattern and rule fields.photo.Lead with the recommended aesthetic. Offer a two-candidate side-by-side only when the speaker is genuinely undecided — not as a default. Comic-book is high-variance: when it works, CTR rises significantly; when it misses, it looks off-brand.
If outline.yaml has a style_anchor block (with full / imgtxt anchor
paragraphs), pass the matching format's anchor paragraph to
generate-thumbnail.py via --portrait-style "<anchor>". The script
pre-stylizes the speaker photo
into the anchor's medium (sepia tech-manual, watercolor, pen-and-ink, etc.)
before composition, so the output palette matches the deck. Without this pass-through, photographic skin tones beside
an illustrated background produce a jarring two-medium composite even when
the aesthetic is otherwise correct.
If Phase 2 didn't produce a style anchor (stock-image-only deck), omit
--portrait-style.
# Single recommended candidate (the precedence-chain winner)
"{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
--slide-image illustrations/slide-15.png \
--speaker-photo ~/photos/headshot.jpg \
--title "JUDGMENT DAY" \
--subtitle "DevNexus 2026" \
--vault ~/.claude/rhetoric-knowledge-vault \
--aesthetic <photo|comic_book> \
--style slide_dominant \
--title-position top \
--brand-colors "#5B2C6F,#C0392B" \
--output thumbnail.png
# Anchor-matched (when the deck has a style_anchor block)
"{python_path}" "{speaker_toolkit_root}/skills/illustrations/scripts/generate-thumbnail.py" \
--slide-image illustrations/slide-15.png \
--speaker-photo ~/photos/headshot.jpg \
--title "JUDGMENT DAY" \
--aesthetic photo \
--portrait-style "<full anchor paragraph>" \
--output thumbnail-anchored.pngApply other speaker preferences from publishing_process.thumbnail:
style_preference → --styletitle_position → --title-positionbrand_colors → --brand-colorsaesthetic_preference is consumed at Sub-step 5 — don't re-apply it.
The script (per invocation, runs once per --aesthetic):
--output, its default filename
follows the emitted format. Retain the actual path and format from its report.Present the generated thumbnail. If rejected, iterate — never regenerate from scratch:
--title-position.If publishing_process.shownotes.enabled is true, the SSG template expects
the thumbnail at a specific path relative to the shownotes site root —
otherwise the live page falls back to a placeholder with no warning.
Resolve the destination using publishing_process.shownotes:
{shownotes.source.path_or_url}/{shownotes.thumbnail_path_template}with {slug} bound to the shownotes page's actual filename stem (the outline's
talk slug for a new page). For Jekyll-based
shownotes the default template is
assets/images/thumbnails/{slug}-thumbnail.png — the nested thumbnails/
subdirectory AND the -thumbnail suffix are both mandatory. Do not strip
either.
For a Jekyll page, retain its actual filename stem when resolving the convention
path, including a legacy date prefix; see the shownotes owner's
placement workflow.
Set {thumbnail_source} to the generator's actual output path and
{shownotes_thumbnail_destination} to the resolved absolute site path. Use the
placement owner for every shownotes write, preserving the local source:
"{python_path}" "{speaker_toolkit_root}/skills/shownotes-publisher/scripts/place-thumbnail.py" \
--source "{thumbnail_source}" \
--destination "{shownotes_thumbnail_destination}"Use the script contract linked by the placement workflow. Require exit 0 and
ok: true before recording its emitted destination path in Sub-step 10. On
failure, apply its reported repair and rerun; never substitute a raw copy.
If shownotes.ssg_template_pointer is set, read that file after a site
redesign to re-derive the path convention. Don't reinvent it from folklore.
Prepare this complete thumbnails[] record from the approved source and
placement receipt; the example values are not defaults:
{
"schema_version": 1,
"talk_slug": "judgment-day",
"youtube_url": "https://youtube.com/watch?v=...",
"source_slide_num": 15,
"speaker_photo_used": "/path/to/headshot.jpg",
"thumbnail_path": "illustrations/thumbnail.png",
"shownotes_thumbnail_path": "assets/images/thumbnails/judgment-day-thumbnail.png",
"dimensions": "1280x720",
"file_size_kb": 185,
"created_at": "2026-04-20",
"approved": true
}Persist it with the ingress owner's upsert_thumbnail mutation, expecting the
exact existing record for the slug or {"$missing": true}. In the same plan, use
update_talk_publishing to set thumbnail_generated: true on the exact talk
filename, expecting its current value. Dry-run the whole plan, review it, apply
against the reported input SHA, and re-read as specified by the
owner mutation contract.
Keep that talk at schema_version: 8. illustrations is an authorized writer of
current thumbnail and talk records; vault-ingress remains their schema owner.
Never rewrite tracking-database.json directly.
.tessl-plugin
rules
skills
cfp-writer
references
illustrations
presentation-builder
presentation-creator
references
patterns
build
deliver
prepare
scripts
presentation-publisher
screencast-editor
screencast-recorder
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile