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
#!/usr/bin/env python3
"""Pack a 0-based speaker-notes JSON map into the SetSpeakerNotes wire format.
Input JSON: `{"<0-based slide #>": "notes text", ...}` — the historical
inject-speaker-notes.py format. Output: a UTF-8 file of records
`<1-based #>US<text>` joined by RS, where US=Chr(31), RS=Chr(30) (non-printing
control chars that don't occur in prose notes). AppleScript reads the file as
UTF-8 and passes it to the SetSpeakerNotes VBA macro, which splits it.
Slide numbers are converted 0-based -> 1-based (python-pptx uses 0-based
indices; PowerPoint VBA uses 1-based). Empty notes are dropped.
Usage:
notes-to-packed.py <notes.json> <out.packed>
"""
import json
import sys
from pathlib import Path
RS = "\x1e" # record separator
US = "\x1f" # unit separator
def pack_notes(notes_map: object) -> str:
"""Return RS-joined `<1-based #>US<text>` records, sorted by slide number.
0-based keys become 1-based; empty notes are dropped. Raises ValueError with
an actionable message on malformed input (non-object map, non-integer key,
non-string text, or text containing the RS/US control chars).
"""
if not isinstance(notes_map, dict):
raise ValueError('notes JSON must be an object {"<0-based slide #>": "text", ...}')
def slide_num(key: object) -> int:
try:
return int(key)
except (TypeError, ValueError):
raise ValueError(f"notes key {key!r} is not an integer") from None
records = []
for key in sorted(notes_map, key=slide_num):
num = slide_num(key)
if num < 0:
raise ValueError(f"notes key {key!r} is negative; slide indices are 0-based (>= 0)")
text = notes_map[key]
if text is None or text == "":
continue
if not isinstance(text, str):
raise ValueError(f"notes for slide {key} must be a string, got {type(text).__name__}")
if RS in text or US in text:
raise ValueError(f"notes for slide {key} contain a reserved control char (RS/US)")
records.append(f"{num + 1}{US}{text}")
return RS.join(records)
def main() -> None:
if len(sys.argv) != 3:
print("usage: notes-to-packed.py <notes.json> <out.packed>", file=sys.stderr)
sys.exit(2)
try:
notes_map = json.loads(Path(sys.argv[1]).read_text())
packed = pack_notes(notes_map)
except (OSError, ValueError, json.JSONDecodeError) as exc:
print(f"ERROR: {exc}", file=sys.stderr)
sys.exit(1)
out_path = sys.argv[2]
Path(out_path).write_text(packed, encoding="utf-8")
count = 0 if packed == "" else packed.count(RS) + 1
print(json.dumps({"records": count, "output": out_path}))
if __name__ == "__main__":
main().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