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.
89
94%
Does it follow best practices?
Impact
89%
1.30xAverage score across 25 eval scenarios
Advisory
Suggest reviewing before use
The custom Jekyll plugin at ~/Projects/shownotes/_plugins/markdown_parser.rb
scans each _talks/*.md file at site-init time and populates a set of
extracted_* fields on the Jekyll document. The talk.html layout
consumes those fields. This file is the line-by-line contract.
If a _talks/*.md file does not start with ---, the plugin's
after_init hook prepends:
---
layout: talk
---This means a talk file CAN technically be markdown-only with no frontmatter — the plugin will fix it on first run by writing back to disk. But this overwrites the file, so always commit the frontmatter explicitly to avoid surprise edits in git status.
# (single hash +
single space)"Untitled Talk""Untitled Talk"title: overrides only if explicitly set in the
frontmatter (the parser checks the raw file for ^title:)extracted_title as the visible page title AND in
the <title> tag AND in the JSON-LD name field^\*\*Conference:\*\*\s*(.+)$ (case-insensitive on the
field name), same for Date[text](url), the URL is returned (relevant for
Slides/Video, not typically Conference/Date)**Field:** value pattern[link text](url) syntax via \[([^\]]+)\]\(([^)]+)\) — $2 is
the URL**Video:** https://youtube.com/watch?v=…) — the
parser returns the full plain text, NOT just the URL. The
embedded_resource.html include then tries to match patterns like
contains "youtube.com/watch?v=", which DOES still work for some
URLs, but the markdown link form is the documented contractnil → the layout's
conditional {% if page.extracted_video %} falls through to the
"Video Coming Soon" badgeCaptured from the ## Abstract section:
## Abstract## heading (including ## Resources)'' in the buffer' ' then run through gsub(/\s+/, ' ').strip**bold**, _italic_, [link](url),
backticks for \code``markdownify in the layout### Subhead) inside abstract are folded into prose- item) flatten to - item - item - item literal textThe legacy fallback parser (extract_abstract_legacy) runs only when
the ## Abstract section is absent — it tries to find content after
the "A presentation at" line. The modern format always uses the
explicit section.
Captured from the ## Resources section:
## Resources\n (newlines preserved)markdownify verbatim — full markdown supported:
### Sub-section)In contrast to abstract, Resources is the place to use structured markdown.
Captured starting from a line that begins with A presentation at:
## or # heading OR the first empty line
AFTER content has been collected' ' (spaces) — multi-line is fineLiquid::Template.parse and
rendered with the site's site_payload — supports liquid
template variables like {{ site.speaker.display_name | default: site.speaker.name }}This is the convention you see across existing entries:
A presentation at GeeCON in
May 2026 in
Kraków, Poland by
{{ site.speaker.display_name | default: site.speaker.name }}If the plugin throws an exception on any field extraction, it sets sane defaults to prevent template errors:
extracted_title ||= page.title || 'Untitled Talk'extracted_conference ||= 'Unknown Conference'extracted_* text fields default to ''So a malformed file will at least render — but every missing field degrades the page. Don't rely on the fallback; structure the file correctly.
Fields present in some files but ignored by the parser:
**Subtitle:** — used in some recent talks (e.g.,
geecon-2026-absolutely-right.md) but not captured into any
extracted_* field. Will render as inline body text after the H1
if the parser doesn't strip it (it doesn't — the metadata-skipping
legacy path applies only when there's no ## Abstract). The
current layout doesn't surface a subtitle anywhere**Co-speaker:** — same as Subtitle; not extracted, not rendered
by the layout<!-- Source: … --> — preserved in the file
body but never rendered (they're HTML comments)If you need a field that the parser doesn't extract today, propose the change at the parser level — don't paper over it in the template.
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
rules
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
vault-profile