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 111-entry Presentation Patterns taxonomy (81 observable: 62 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns) for scoring, brainstorming, and go-live preparation.
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
#!/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:
# JSON object keys are strings; an int key can only come from a manifest
# built in-process. Anything else takes the same rejection path it
# always did, now without asking int() to consume an arbitrary object.
if isinstance(key, (str, int)):
try:
return int(key)
except ValueError:
pass
raise ValueError(f"notes key {key!r} is not an integer")
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().tessl-plugin
rules
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile