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
This is the complete normative Step 1 contract for vault-ingress. Execute
each section in order; later sections assume every earlier gate succeeded.
Vault discovery — canonical path is always ~/.claude/rhetoric-knowledge-vault/.
vault_root, then load the database with the strict
owner read command in
schemas-db.md.AskUserQuestion,
create the directory (and symlink if a custom path was chosen), then use a sole
initialize_database mutation. Include database schema_version: 1, config
schema_version: 2, and empty talks, pptx_catalog, qr_codes, resources,
thumbnails, confirmed_intents, and improvement_goals arrays. The plan may
omit pptx_directory_exclusions; the initializer supplies the canonical default
defined by the PPTX scan contract. Include that field
only when the speaker explicitly requests a valid customization.
Review the dry-run and apply it with --expected-sha256 missing; never create
the JSON file directly.Schema gate — vault-ingress owns the tracking database shape and migrations.
The stdlib-only strict reader may use the host interpreter for the initial
bootstrap read only. Read config.python_path from an existing database, or ask
for the interpreter path without writing the database when that field is absent.
Immediately re-read the same canonical path with that configured interpreter and
require the same SHA-256; restart discovery if the generation changed. Use the
configured interpreter for migration, queue commands, and every later toolkit
command. Run the owner migration before any other database mutation:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/migrate-tracking-database.py" \
"{vault_root}/tracking-database.json"Exit 0 writes one dry-run JSON report with input_sha256, source and target
schema versions, output_sha256, record_counts, changed,
database_written: false, warnings, and the deterministic backup path. A
changed report authorizes this exact apply command:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/migrate-tracking-database.py" \
"{vault_root}/tracking-database.json" --apply --expected-sha256 "{input_sha256}"Exit 0 from apply writes one JSON report with database_written: true, preserves
the complete original bytes under {vault_root}/.backups/, and atomically
installs database schema v1 with config schema v2. A current root with config
schema v1 is also a migration: root from_schema_version and
to_schema_version both remain 1, while record_counts.config records the
config upgrade. A non-empty warnings array means replacement
completed with a durability warning and must not be reported as a failed/no-write
run. Exit 2 writes one error object to stdout plus a diagnostic to stderr and
leaves the database unchanged. Recover or
complete every active queue claim named by the diagnostic. For an unversioned
database, use queue-state.py ... inspect to identify the lease and
queue-state.py ... recover to close it. Those two commands accept schema 0;
recovery changes only queue-lease/status state and does not stamp or migrate the
database or talk record. The existing queue transition may advance a recovered
legacy claim receipt from schema v1 to v2 while adding its release fields. Rerun
migration dry-run, then apply its new exact digest. Do not copy a digest across
runs. queue-state.py ... normalize and queue-state.py ... claim require
database schema 1.
Config bootstrapping — ask once per missing user-owned field and persist to the tracking
database with expectation-bound set_config mutations. Re-read after every
successful apply and use the new hash for the next plan. Core fields: shownotes (enabled, source.type, source.path_or_url,
source.talks_subdir, url.base, url.template, thumbnail_path_template,
slug_convention), pptx_source_dir, python_path, template_skip_patterns,
and pptx_directory_exclusions. The exclusion field is not a missing-field
question: initialization supplies the canonical default, while migration supplies
that default when absent or preserves an existing valid custom list. Ask about or
change it only when the speaker explicitly wants to customize directory pruning.
See schemas-db.md for the full schema and
schemas-config.md for
field-by-field semantics and migration notes.
python_path is the interpreter authority for every operational command below;
never fall back to whichever python3 happens to be on PATH. Installed plugin
bundles do not include pyproject.toml, so immediately probe the configured
runtime with the shipped stdlib-only checker:
Remove obsolete config fields with delete: true; never pass the missing marker
as a value. If the owner read exposes that marker as a present legacy value,
use the expectation-bound deletion in
schemas-db.md, then re-read
before another config write.
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/check-runtime.py" \
--lanes core,pdf,pptxAll owner-authored tracking writes below require database schema 1 and config
schema 2 after this
gate. Preserve every independent record version and validate the complete
candidate before installing it. Only migrate-tracking-database.py may move
schema 0 to schema 1; its hash precondition binds replacement to the exact input
bytes as documented above.
Core requires Python 3.10+ and PyYAML and is blocking. The PDF lane requires
pypdf plus exactly psutil==7.2.2; the PPTX lane requires python-pptx plus the
same exact psutil version. Both parser lanes run behind bounded worker
supervision. Preserved source-video evidence has its own narrow source-video
lane requiring exactly psutil==7.2.2 plus ffprobe; require that lane before
preflight, persistence, queue, or profile work will inspect a local recording
declared by structured_data.video_extraction.source_video_path,
video_local_path, or video_path.
The canonical vault locator may be the configured symlink; the PDF
boundary maps that trusted root to storage while still rejecting every
descendant symlink/reparse redirect. Trusted-root bindings retain the directory
object's stable identity and policy attributes, not mutable child-content size or
timestamps; PDF and PPTX leaf generations remain exact. The checker emits report
schema v2 and records exact pins under
each lane's required_module_versions; a mismatched version is unavailable. A
missing optional lane is reported as degraded and must not erase a healthy
transcript or alternate slide lane.
Require a lane before using it, for example --require-lanes core,pdf. Remote
Drive acquisition additionally needs the gdown module; captions need
youtube-transcript-api; audio download fallback needs yt-dlp; rendered PDF
inspection needs pdftoppm; video extraction needs exactly Pillow==12.3.0,
ImageHash==4.3.2, numpy==2.2.6, and filelock==3.32.2, plus ffmpeg and
ffprobe; local Whisper needs mlx-whisper and ffprobe.
Inspect those with the checker's google-drive, captions,
youtube-download, pdf-render, video, and whisper lanes as selected talks
require; use source-video for evidence over an already-preserved recording and
video for frame extraction. Each lane is independent: a failed optional
import/tool disables only that lane. Import failure details appear under the
lane's module_failures;
dependency absence, initializer exceptions, native crashes, timeouts, and
invalid child results degrade an optional lane or block a required lane without
breaking the one-JSON contract. The checker writes a recovery instruction to
stderr whenever a lane is unavailable.
Scan for new talks: run the deterministic scanner in its default read-only mode:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/scan-shownotes.py" \
"{vault_root}/tracking-database.json"Read the structured report before any mutation. add and update entries are
safe deterministic proposals; review_required entries need a human decision.
The scanner uses exact filename identity, derives supported YouTube and Google
Drive IDs, and keeps every matching source_rejections identity inactive.
For comparison only, title equality applies Unicode NFC and maps straight/curly
single and double quote glyphs to the same narrow equivalents. It preserves
case, other punctuation, and wording. Conference equality applies NFC plus
casefold only and preserves whitespace. The scanner never writes these
comparison transforms back to the database or report. Incomplete metadata,
substantive conflicts, and normalized filename collisions remain proposals.
Disabled, remote_url, and none sources return a structured no-op.
For an exact-filename match, pass the stored and proposed title plus stored
conference/date context to the shared title-agreement contract documented in
schemas-db.md. Agreement keeps the
authored title unchanged. Disagreement emits existing_title_conflict and
leaves the entry review_required.
Apply the reviewed deterministic proposals with the same command plus
--apply. Only add and update entries mutate the tracking database. New
records receive current schema_version and status "pending"; exact-filename
updates fill empty fields without overwriting established values. The write is
atomic and rejects a tracking-database symlink. See
schemas-db.md
for the complete report and mutation contract.
Scan for .pptx files: Do not recursively glob the source tree. Run one bounded directory extraction, which owns deterministic discovery, symlink/reparse-point rejection, and aggregate file/input/output/wall budgets:
Read the exact config.template_skip_patterns and
config.pptx_directory_exclusions arrays from the strict owner-read result.
Set {template_skip_arguments} to one separately shell-quoted
--skip=<exact-value> argument per array entry, preserving its order. An empty
array produces zero arguments; never add an implicit default.
Set {directory_exclusion_arguments} the same way, using one
--exclude-directory=<exact-component> argument per exclusion. These are
case-insensitive exact directory-name components at any descendant depth—not
substrings, paths, globs, or regular expressions. The sole config-v2 owner-default
source is
skills/vault-ingress/scripts/pptx_discovery_contract.py::DEFAULT_PPTX_DIRECTORY_EXCLUSIONS;
do not copy or reconstruct that list in workflow prose.
Do not broaden that code-owned default to plausible authored-content directory
names without an explicit speaker-specific customization.
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/pptx-extraction.py" \
--directory "{pptx_source_dir}" {template_skip_arguments} \
{directory_exclusion_arguments}Require exit status zero before consuming the public schema-v1
pptx_directory_batch envelope's results[] or skipped[]. A
whole-root discovery failure exits nonzero and emits a compact top-level
error containing the public reason_code plus any closed
details.supervisor_reason_code; report both and stop the PPTX scan. Never
reinterpret that failure's root skipped[] receipt as a successful empty scan.
On exit zero, complete is true exactly when incomplete_reason_codes is
empty. A partial scan deliberately still exits zero so its safely extracted
per-deck results can be reviewed and persisted. Preserve those results and all
skip receipts, report the incomplete reasons, and rerun after remediation. Only
complete: true proves that all eligible descendants were considered; without
it, never claim full catalog coverage, infer that a missing deck does not exist,
or convert an empty result into an absence conclusion. Legacy unversioned
{"results": ..., "skipped": ...} output has unknown completeness and must be
rerun before any coverage or absence claim.
Use root-relative results[].pptx_path identities to fuzzy-match talks[] entries
and retain every skipped[] receipt. Treat the envelope's complete and
incomplete_reason_codes fields as authoritative; never reclassify receipts by
reason string. Configured exclusion dirents use a separate bounded
policy-enumeration allowance rather than the eligible-entry budget, so policy
pruning cannot hide an authored sibling; exhausting that allowance fails closed.
Directory intent must remain explicit:
do not omit --directory or
pre-probe the root with find, a recursive glob, or a per-file loop. The bounded
authenticated discovery worker owns root validation and enumeration. Report counts,
then persist each reviewed result with a record_pptx
mutation and schema_version: 2, including the exact prior catalog record and, for
a match, the talk's exact prior pptx_path expectation. A record whose deck has
had no extraction attempt carries visual_evidence: null; a record claiming
visual evidence carries the receipt binding extractor schema, pipeline version,
exact source fingerprint, and artifact identity. Never decide from
visual_extracted alone whether a deck needs extraction. Run:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/classify-pptx-evidence.py" \
"{vault_root}"It fingerprints each deck and each extraction artifact on disk, classifies
every catalog record, and prints one JSON object; extract exactly the records
whose needs_extraction is true. Argument, output shape, and exit codes are in
the script's module docstring. A legacy record's bare claim reads as
unknown-generation evidence, and an unreadable deck or a deleted artifact reads
as unverified — never as current (see schemas-db.md —
pptx_catalog v1 -> v2). See
schemas-db.md for the PPTX extraction output
schema (per-slide visual data, shape types, global design stats).
Consume current schema v4. A v0/v1 record has unknown timing, not zero timing;
v2 has the pre-build timing lanes but lacks raw build-list evidence,
archive-recovery, and exact native/render audit receipts; v3 lacks required
shape/image capability bindings. Regenerate v0-v3
output for current analysis. An unknown future
schema is unusable until this reader is updated. The vault-profile layout-only
consumer is the documented v1/v2/v3/v4 exception for the unchanged
template_layouts field. Non-empty archive_recovery is degraded evidence:
restore or re-export a required native deck before claiming or returning it.
Pattern taxonomy recovery: See processing-rules.md for the queue-owned
contract. Step 2 normalization deterministically routes processed results outside
the active pattern-scoring generation back to needs-reprocessing; do not infer
generation currency from processing date or hand-edit those statuses.
Pattern catalog preflight: Before source selection or re-analysis, run:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/audit-pattern-catalog.py"Stdout is stable JSON. Exit 1 means structural catalog errors: stop before
scoring. Exit 0 may include semantic_debts; present those for human review and
do not auto-edit names, aliases, definitions, or graph relationships. The input,
report, and no-write contracts are defined in
pattern-catalog-contract.md.
Conditional source-video runtime gate: Use only the strict owner-read database
payload to determine whether the upcoming source preflight may inspect any
preserved local recording declared by
structured_data.video_extraction.source_video_path, video_local_path, or
video_path. When it may, require the configured runtime before invoking
preflight:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/check-runtime.py" \
--lanes core,source-video --require-lanes core,source-videoDo not pre-open, hash, hydrate, or invoke ffprobe directly on the recording.
The supervised source-video assessor owns availability, exact-generation hashing,
media inspection, caching, and diagnostics. Repair a failed required lane before
allowing preflight to inspect that recording. An unavailable or unreadable video
disables only source-video evidence; it must not erase or invalidate independently
verified transcript, rendered-PDF, or native-PPTX evidence.
Source/identity preflight: After bootstrapping and scanning, and before talk selection or re-analysis, run the read-only offline gate:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/preflight-vault.py" {vault_root}Exit 1 means one or more blocking integrity errors (identity disagreement,
unqualified duplicate recording, invalid source claim, or a claimed completed
artifact that is missing): stop and repair those records/artifacts before
processing. Exit 0 may still carry warnings for legacy evidence gaps or pending
artifacts; report them, but they do not make the vault unusable. Exit 2 carries
a real report whose single blocking preflight_unexpected_failure finding means
the gate never completed — treat the vault as unverified, not clean, per
Entrypoint Failure Contracts. The stable JSON
report and evidence shape are defined in
source-identity-preflight.md.
After the offline gate, capture and compare live YouTube provider evidence:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/audit-source-identities.py" {vault_root}This networked audit invokes yt-dlp once per distinct active YouTube ID and
prints deterministic JSON without changing the vault. Review every proposed
source_identity block and finding, especially likely_non_delivery_clip and
same_id_cross_talk_collision. Provider uploader is not speaker evidence,
upload date is not recorded date, and the provider webpage URL must never be
auto-applied as an active source. See
source-identity-audit.md.
Only after that human review, write a source-repair plan containing supported facts and exact old-value preconditions, then dry-run it before applying:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/apply-source-repairs.py" \
{vault_root}/tracking-database.json source-repair-plan.json
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/apply-source-repairs.py" \
{vault_root}/tracking-database.json source-repair-plan.json --applyThe apply command validates the whole plan before mutation, refuses active queue
claims, writes a byte-for-byte backup under {vault_root}/.backups/, and replaces
the DB atomically. Re-run the preflight after applying; do not claim work until
blocking findings reach zero.
The summary's status block is owner-generated, never hand-edited. Refresh it at safe checkpoints — after migration or recovery, after normalization, and after a batch persists — with:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/render-vault-status.py" \
"{vault_root}" --generated-at "{iso_timestamp}"That is a dry run: it writes nothing and prints one JSON object on stdout.
--summary overrides the summary path; --generated-at is required and is
recorded in the block, so a render is reproducible.
The report fields this workflow reads:
summary_sha256 — the digest to pass back as --expected-sha256changed — false means the installed block already matches; skip the applysummary_written — true only after an apply installed new bytesstatus — the derived counts, and block the exact text that would installApply with the digest the dry run reported:
"{python_path}" "{speaker_toolkit_root}/skills/vault-ingress/scripts/render-vault-status.py" \
"{vault_root}" --generated-at "{iso_timestamp}" \
--apply --expected-sha256 "{summary_sha256_from_dry_run}"Exit 0 succeeded. Exit 3 is the precondition alone: the summary's bytes are no
longer the ones the digest named, so re-run the dry run and apply with the new
digest — never force it. Exit 2 is every other failure — the database or the
summary could not be read, locked, or installed — and its JSON carries a typed
code plus an actionable error; act on that, do not retry blindly.
The block carries the database SHA-256 it was derived from, so a consumer can tell a stale block from a current one; the tracking database stays the authority and prose counts are never trusted on their own.
Read rhetoric-style-summary.md and slide-design-spec.md. Report:
"X processed, Y remaining. PPTX: A cataloged, B matched, C extracted."
.tessl-plugin
rules
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
references
scripts
vault-profile