CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

jbaruch/speaker-toolkit

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).

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

qr-generation-rules.mdrules/

alwaysApply:
No
applyTo:
skills/presentation-publisher/** — when generating or replacing QR codes during the presentation publishing flow

QR Generation Rules

1. ALWAYS Use generate-qr.py

NEVER call the qrcode library directly or generate QR images through any other means. ALWAYS use generate-qr.py. The script handles URL shortening, custom back-half, tracking DB updates, color matching, and secrets.

When the target is not a .pptx deck (e.g., presenterm, PDF, or standalone PNG), use --png-only mode:

python3 generate-qr.py --png-only --talk-slug SLUG --shownotes-url URL \
    --output /path/to/qr.png --bg-color "128,0,128"

2. NEVER Use a Random Shortener Hash

The short link's back-half MUST ALWAYS be the talk slug — the bit.ly custom back-half AND the rebrand.ly slashtag, with no override. When a custom domain is configured in the vault profile (bitly_domain / rebrandly_domain), the short link MUST use it. The script does this automatically: --talk-slug devnexus26-robocoders with bitly_domain: jbaru.ch creates jbaru.ch/devnexus26-robocoders (not bit.ly/a3xK9f).

When the slug back-half cannot be set:

  • The script exits non-zero without generating a QR.
  • It reports the already-created provider-side link's link_id and short_url.
  • It never keeps a random hash.
  • It never degrades to a raw URL. Only an explicit "shortener": "none" authorizes raw encoding (§3).

Random hashes are untraceable and unprofessional. The back-half IS the slug.

3. QR Always Encodes the Shortener URL

The QR code MUST encode the bit.ly/rebrandly URL, never the raw shownotes URL. The shortener is the decoupling layer — if the shownotes URL changes later, update the shortener target, and every printed QR code stays valid.

The only exception is "shortener": "none" (explicit opt-out), where the raw URL is the only option.

--shownotes-url is required in every mode, including MCP-preresolved. It is the canonical redirect target the catalog records; the short URL never stands in for it.

4. Catalog Every Generated Artifact

The qr_codes record MUST describe what was actually produced:

  • Record the exact path each PNG was written to, never a default filename.
  • Record path_root explicitly (deck_dir, cwd, or absolute).
  • Record every colour variant a run generates, not only the first.
  • Record a SHA-256 per artifact so a stale replacement is distinguishable.
  • Record the issuing provider and its link id. mcp_preresolved is a last-resort marker for when the agent supplies neither.
  • Record short_path as the short URL's back-half, which §2 requires to equal the talk slug. A pre-resolved link whose back-half differs stops the run under §2; it is never recorded with the slug asserted onto it.

5. Slug Convention

The back-half IS talk.slug — composed and agreed with the author in Phase 1 (per the speaker's slug_convention.template) and persisted in outline.yaml. The QR step uses it VERBATIM: never invent, rephrase, re-derive, abbreviate, or date-prefix it. The back-half must equal the published shownotes slug.

  • Kebab-case, lowercase, no special characters
  • No date prefix (e.g. devnexus26-robocoders, not 2026-04-16-devnexus-robocoders)

6. Missing Shortener Config = STOP

When the speaker profile has no shortener configured (key missing, not set to "none"), STOP and ask the user to choose one.

  • "shortener": "none" → explicit opt-out, proceed without shortening
  • shortener key missing → NOT CONFIGURED → ask before proceeding

Silent generation with a raw URL when shortening was never discussed = failure.

7. Missing API Token = STOP

On the direct API path, if secrets.json is missing or lacks the selected shortener's token, STOP and guide the user to create it. MCP-preresolved links and explicit shortener: none do not require direct API tokens. Do not silently degrade to a raw URL.

The script prints actionable creation commands — but the agent must treat a missing token as a blocker, not a fallback trigger.

8. First Short Link = ASK + SAVE the Custom Domain

The first time a short link is created for the active shortener, the custom-domain decision MUST be recorded in the vault profile. Three states of publishing_process.qr_code.{shortener}_domain:

  • Key ABSENT → never asked. ASK whether the user has a custom domain (e.g. jbaru.ch) and SAVE the answer before the link is created.
  • A domain string → use it for the short link.
  • null → recorded decision: no custom domain, use the shortener default (bit.ly).

Save the decision either way — the domain string, or null for "no custom domain". A null is a recorded decision, not an absent value; never re-ask once saved. On the Direct API path generate-qr.py STOPS when the key is absent; on the MCP path the agent makes the same check before resolving the link.

9. Replace Only Tracked QRs, In Place

  • Replace every tracked QR at its own position and size, on the closing slide and on any earlier slide.
  • Never add a second QR beside a tracked one.
  • A tracked QR encodes a short_url or target_url from qr_codes, or one of this run's own URLs.
  • Leave every other QR untouched: an organizer's survey QR, a sponsor's registration QR, a code from another generator.
  • Delete a stale untouched QR by hand; the run names its slide.
  • The run stops before any provider call when the new QR would overlap an untouched QR.
  • The run stops before any provider call when replacing a tracked QR would delete another picture at that QR's position and size.
  • generate-qr.py owns QR identification and its thresholds.

10. The Closing Slide Is the Last Visible One

  • closing and both target the last slide the audience sees.
  • Hidden slides after the close don't count.
  • When detection picks the wrong slides, pass --slides N[,N...]: the listed 1-based slides replace detection.
  • A tracked QR outside --slides stays in place, and the run names its slide.

README.md

tile.json