Agent skill

Demo Reel

by vfarcic in vfarcic/dot-agent-deck

Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube.

MITAuto-check: notes

Install Demo Reel

skills CLI
$ npx skills add vfarcic/dot-agent-deck --skill demo-reel -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install vfarcic/dot-agent-deck demo-reel --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/vfarcic/dot-agent-deck.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/demo-reel .claude/skills/demo-reel && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
demo-reel
GitHub stars
109
Token cost
~5.2k tokens
SKILL.md length
2,993 words
Files
8
Skills in repo
23
Repo updated
First seen
Licence
MIT

At a glance

Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube.

  • Works in 2 steps: Card. A synthetic asciinema cast paints… → Clip. A .cast is first re-timed…
  • Asked to build a demo reel / narrated video from a set of asciinema casts
  • SKILL.md covers Usage, Manifest contract, Prerequisites and How a reel is built, plus 7 more sections
  • Runs Shell scripts from its folder; calls ffmpeg; reaches youtu.be; needs YOUTUBE_CLIENT_SECRET and YOUTUBE_REFRESH_TOKEN

What it does

Demo Reel is an agent skill from vfarcic/dot-agent-deck. Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube. Repo-agnostic engine driven only by a manifest.json; runnable by an agent or directly as reel.sh. Use when asked to build a demo reel / narrated video from a set of asciinema casts, gifs, or mp4 clips.

Its SKILL.md is about 5.2k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files (for example `reel.sh`, `retime.sh` and `tests/fixtures/manifest.json`).

It works with YouTube. The repository describes itself as: A rich terminal dashboard for monitoring and controlling multiple AI coding agent sessions. The licence is MIT.

When your agent uses it

  • Asked to build a demo reel / narrated video from a set of asciinema casts

Example prompts

  • “/demo-reel”

Requirements

  • A Bash shell
  • A credential in YOUTUBE_CLIENT_SECRET
  • A credential in YOUTUBE_REFRESH_TOKEN

Workflow steps

2 steps, taken from the first numbered list in SKILL.md.

  1. Card. A synthetic asciinema cast paints the bold bright-cyan title and a
  2. Clip. A .cast is first re-timed (retime.sh rewrites its event

What it can do on your machine

Read from SKILL.md and the folder at commit 9cc3e60. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • ffmpeg

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • youtu.be

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • YOUTUBE_CLIENT_SECRET
    • YOUTUBE_REFRESH_TOKEN

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Demo Reel loads about 5.2k tokens when it runs. Until then it costs about 92 tokens; SKILL.md has 2,993 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~92
When it runs · the whole SKILL.md, loaded when a task matches
~5.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NoteMentions a .env fileSKILL.md:79
    his repo they are sourced from `vals` / `.env.vals.yaml`:

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from vfarcic/dot-agent-deck at commit 9cc3e60, republished under its MIT licence (© vfarcic). 2,993 words, ~5,202 tokens.

Download SKILL.mdSave it as .claude/skills/demo-reel/SKILL.md (or your agent's skills folder). This skill also uses 7 other files; get the full folder from GitHub.
name
demo-reel
description
Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube. Repo-agnostic engine driven only by a manifest.json; runnable by an agent or directly as reel.sh. Use when asked to build a demo reel / narrated video from a set of asciinema casts, gifs, or mp4 clips.

Demo Reel engine

A reusable, repo-agnostic engine that turns an ordered manifest of {title, description, clip} entries into a single narrated MP4: for each entry it renders a title/description card, plays that entry's clip, then moves to the next — concatenated in manifest order. With --publish it uploads the result private to YouTube and prints the URL.

The engine knows nothing about Rust, tests, PRDs, or any specific repo. Its only input is a manifest.json. It is invocable by an agent (via this skill) and directly by a human or CI (reel.sh manifest.json --out reel.mp4).

Status: the full engine pipeline is wired. A run validates the manifest and prerequisites, renders a card per entry, stitches [card, clip, …] into one uniform MP4 (reel.sh → ffmpeg), and — with --publish and credentials present — uploads it private to YouTube (upload.sh) and prints the URL. The stitch path is covered by a re-runnable local smoke (task reel-smoke); the live upload is verified by code review plus a documented one-line manual step (see Verifying the upload path).

Usage

sh
reel.sh MANIFEST [--out OUT.mp4] [--title TITLE] [--publish]
Argument / optionMeaning
MANIFESTPath to a manifest.json (see Manifest contract below). Required, positional.
--out OUT.mp4Where to write the stitched MP4. Default: reel.mp4.
--title TITLETitle for the uploaded video (used only with --publish). Default: the basename of --out without its extension (e.g. reel for reel.mp4). The engine is repo-agnostic and has no notion of a PRD, so a descriptive title is the caller's job — the dot-agent-deck adapter composes one and passes it through here.
--publishAfter stitching, upload the MP4 private to YouTube and print the URL. Requires the YouTube OAuth credentials (see Prerequisites).
-h, --helpPrint usage and exit.

Examples:

sh
reel.sh manifest.json --out reel.mp4                                   # stitch only, no upload
reel.sh manifest.json --out reel.mp4 --publish                         # stitch + upload private (title = "reel")
reel.sh manifest.json --out reel.mp4 --title "My demo reel" --publish  # stitch + upload with an explicit title

Manifest contract

manifest.json is the only contract between a caller and the engine. It is a JSON array of one or more objects, in the order the segments should appear:

json
[
  {
    "title": "mouse/button/001 — inline-shortcut label",
    "description": "Start the app, focus the dashboard, and confirm the Button widget renders its inline-shortcut label.",
    "clip": "recordings/mouse-button-001/full-stream.cast"
  },
  {
    "title": "Second segment",
    "description": "What this clip shows, in 1–3 plain-English sentences.",
    "clip": "clips/second.mp4"
  }
]

The engine rejects a manifest that breaks any of these rules, with a specific message and a non-zero exit:

  • The top level is a non-empty JSON array.
  • Every entry is a JSON object with non-empty string title, description, and clip.
  • clip is a path to an existing .cast (asciinema v2), .gif, or .mp4 file. Paths are resolved relative to the current working directory. The format is intentionally open: a cast renderer is just one optional front-end, so an already-rendered gif/mp4 can be fed directly (this is what lets a different recording tool reuse the same engine).

Prerequisites

The engine checks these before doing any work and fails fast with an actionable message naming exactly what is missing; it never self-installs anything.

Always required (CLIs on PATH):

CLIUsed forPackage
aggrender an asciinema cast to framesnix asciinema-agg
ffmpegstitch and encode the final MP4nix ffmpeg
jqparse and validate the manifestnix jq
curlupload to YouTube (only with --publish)nix curl

Required only with --publish — YouTube Data API v3 OAuth credentials, read from the environment (never hardcoded). In this repo they are sourced from vals / .env.vals.yaml:

Env varMeaning
YOUTUBE_CLIENT_IDOAuth client id
YOUTUBE_CLIENT_SECRETOAuth client secret
YOUTUBE_REFRESH_TOKENOAuth refresh token (minted once via a human consent flow)

Stitch-only runs (no --publish) do not require any credentials. The one-time OAuth provisioning is documented in docs/develop/demo-reel.md.

How a reel is built

For each manifest entry, in order:

  1. Card. A synthetic asciinema cast paints the bold bright-cyan title and a bright-white, left-aligned, vertically-centered description as terminal text, on the engine's own fixed CARD_COLSxCARD_ROWS grid (84x20 — shaped ~16:9 in character cells so a card fills the output canvas rather than letterboxing inside it). CARD_ROWS is a minimum: a long description grows the grid taller and the font shrinks to match, so text scales instead of clipping. The card's hold duration is a flat CARD_HOLD seconds (default 4s, env-overridable), independent of how much text the card carries: a fixed, deliberately short hold keeps the reel moving, and a viewer who wants to read a long description pauses the video rather than the reel parking on every long card. The hold is enforced at the ffmpeg level — a single painted still is frozen from the rendered card and looped to exactly the hold duration — so it is decoupled from agg's idle handling (which would otherwise collapse the static tail to a couple of seconds).
  2. Clip. A .cast is first re-timed (retime.sh rewrites its event timestamps for a watchable cadence — see below), then rendered through agg at its recorded terminal grid; a pre-rendered gif/mp4 is used as-is (no re-timing).

Both are rendered at an agg font size fitted to the output canvas, not a fixed one. A terminal grid carries no pixel size of its own, so choosing the font is how the engine gets glyphs rasterized at output resolution: a 68x16 cast at font 16 is only 674x381, which on a 1080p canvas is a ~2.8x upscale of already- rasterized text (mush); at the fitted font (45) it renders 1896x1071 and stays sharp. Set CLIP_FONT_SIZE / CARD_FONT_SIZE to pin a font and skip the fit.

Clip re-timing

e2e casts are recorded at machine speed, so their raw timeline is unwatchable: a keypress and the full repaint it triggers land within a millisecond of each other, while short real waits (daemon startup, polling, debounce) sit between them. A single global agg --speed cannot fix this — slowing everything stretches the waits into dead air and still cannot spread coincident events apart. So before rendering, every .cast clip is passed through retime.sh, which rebuilds the timeline from the event payloads (rendering then runs at CLIP_SPEED 1.0):

The contract: the re-timer re-distributes time, it does not manufacture it. Time reclaimed from dead air is re-spent holding operations, so the output totals about max(MIN_BUDGET, the input duration) — and never more than max(MIN_BUDGET, MAX_STRETCH × input), which is a hard ceiling that compresses everything proportionally if the base gaps alone would exceed it. When there is no dead air to reclaim, nothing is held and the clip plays at roughly real time. No cast can come out as a slideshow.

Two measured worked examples. A 28.7s cast of a real agent working, already smoothly paced (no gap over 0.03s), comes out at 32.3s — 1.12×, essentially unchanged. A synthetic cast of 6 repaints separated by 3s waits — 15s that is almost entirely dead air — comes out at 7s, with each repaint held the full OP_HOLD 1.4s: the waits are gone, every operation is now visible, and the whole thing is shorter than the original.

Each event is classified into one of three kinds, by payload size and content:

  • op — a payload larger than SIZE_THRESHOLD bytes is a full-region repaint (opening a deck/form/pane). Consecutive large chunks within COALESCE_GAP of each other are one logical repaint and are coalesced into a single step. An op is held after the repaint (up to OP_HOLD) so the new state is actually visible — budget permitting.
  • type — a small payload that actually prints something is a typed character (ratatui emits a minimal diff per keypress). Each gets its own step, at least TYPE_GAP apart, so typing replays at a readable speed.
  • tick — a small payload that prints nothing: pure control sequences (SGR reset, show-cursor, cursor-position). That is the render loop's per-frame tail, not a keystroke, so it keeps its original gap (clamped to IDLE_CAP) and is never spread.

Any single gap is clamped to IDLE_CAP, which is what kills dead air while still reading as a pause.

The final frame is held for a sized beat, not agg's default. Left alone, agg holds a clip's last frame for its default --last-frame-duration (3s in the pinned 1.9.0) on top of whatever tail the cast already spends on that final state — issue #365 measured PRD #341's reel ending on 5.27s of one identical frame, ~2.2s of cast tail plus agg's hold. So reel.sh sizes the hold per clip. It asks retime.sh --trailing how many seconds the retimed cast runs after its last visible change, renders the cast with that tail cut out (retime.sh --cut-tail moves the tail's events onto the last change's timestamp, so their cursor state still lands in the final frame), and passes --last-frame-duration max(CLIP_FINAL_DWELL, tail + CLIP_LAST_FRAME). The tail is folded into the hold rather than left in the cast because agg emits a frame only when the image changes: a tail of ticks that move nothing renders as no time at all, while one whose ticks move the cursor renders up to the last move, and telling the two apart takes a terminal emulator. CLIP_LAST_FRAME (default 1s) is the closing beat after the tail; CLIP_FINAL_DWELL (default 2s) is the least total time the final state stays on screen. The floor is for a cast that ends on its payoff — a test that stops recording the moment its assertion matches paints the answer at or near its last event, with little or no tail, and would otherwise show it for about one second. At the defaults, a cast with a tail of at least 1s gets nothing from the floor, so a clip with issue #365's ~2.2s tail ends on ~3.2s of final state instead of 5.27s. Both are env-overridable, in seconds of reel time (the tail is divided by CLIP_SPEED, which agg applies to the cast but not to its last-frame hold). Cards are unaffected: their hold is CARD_HOLD, enforced at the ffmpeg level.

A visible change here is any event that is not inert, and inert is deliberately narrower than the re-timer's tick: only SGR attributes (which affect later writes, not what is painted), cursor show/hide, and cursor positioning or movement — the render-loop tail. A tick is anything that prints no characters, which also covers erase, scroll and newline; those do change the screen, and counting them as tail would overstate how long the final state has been up and shorten its hold.

Why content and not size alone. PRD #339's published reel turned a 15.5s cast into a 161s video (10.4×), and the classifier is why: it called every small payload a keystroke. A ratatui render loop emits a per-frame tail of SGR-reset + show-cursor + cursor-position that prints nothing at all, and those tails are the overwhelming majority of a cast's events — so each was given its own 100ms "typed char" step, and each coalesced repaint was then unconditionally held 1.4s on top. Re-measured on that test's replacement recording (28.7s, 1621 events: 1565 ticks, 44 real typed chars, 12 repaints), the old re-timer produces 172.4s — 1609 × 0.1s of fabricated typing cadence, which is ~93% of the total — while the new one produces 32.3s. Both failure modes are closed: tick events are no longer mistaken for typing, and OP_HOLD is granted only out of reclaimed slack under the duration budget.

retime.sh is repo-agnostic (it operates on any .cast) and standalone (retime.sh [INPUT.cast] [--out OUT.cast] [--trailing | --cut-tail], reading stdin / writing stdout by default; --trailing and --cut-tail measure and remove the final-state tail described above instead of re-timing). Its tunables are env-overridable, like the engine's CLIP_SPEED — SIZE_THRESHOLD (80) is in bytes, MAX_STRETCH (1.6) is a ratio, everything else is in seconds: TYPE_GAP (0.1), OP_HOLD (1.4, a maximum now), IDLE_CAP (0.4), MIN_BUDGET (8), COALESCE_GAP (0.05). (IDLE_THRESHOLD is gone — every gap is simply clamped to IDLE_CAP, so there is no separate "is this a real wait" threshold.) CLIP_SPEED (default 1.0) remains as a global multiplier layered on top of the re-timer for the rare clip that wants a uniform nudge; note that it multiplies duration outside the re-timer's budget.

Show full SKILL.md (1,098 more words)Show less

Output canvas

Every segment is then normalized (ffmpeg scale + pad) to one common resolution at a constant fps and yuv420p, so all segments share resolution/fps/pixfmt and concat into a single uniform stream (reel.mp4 by default).

That resolution is a fixed, landscape 16:9 canvas — REEL_WxREEL_H, default 1920x1080, a normal laptop screen — and is deliberately not derived from the segments. It used to be the per-axis max across every native segment, which silently produced a canvas whose aspect ratio belonged to neither a card nor a clip: PRD #339's reel took its width from the card (1140) and its height from a portrait 60x50 clip (1142), came out 1140x1142, and showed the terminal in a ~585px centre strip with black bars either side.

Segments are fit into the canvas (scale preserving aspect, then pad) and are never cropped — cropping a terminal would cut off content. So the canvas fixes the frame, but how much of it a clip fills remains a property of the recording:

  • A ~16:9 cast fills it nearly edge to edge. In character cells that is roughly 4x as many columns as rows (a cell is about 1:2.3), e.g. 68x16 or 200x50.
  • A portrait cast can only ever occupy a centre strip. A 60x50 terminal is 0.52:1 against a 1.78:1 canvas and covers ~29% of the frame — no engine setting can fix that; it has to be re-recorded.

The engine warns (non-fatally, per segment) when a clip's aspect is more than ASPECT_TOLERANCE (1.35) off the canvas, naming the percentage of the frame it will actually cover.

Checks the engine runs for you

Every run reports these to stderr, so a bad artifact is visible before it is published rather than after someone watches it. All are non-fatal — the engine's job is to render what it was given — but each one names a specific thing to fix:

CheckWhat it catches
Cast integrity — a cursor-position escape (ESC[row;colH, ESC[colG) addressing a column beyond the cast header's widthThe terminal was resized mid-recording. asciinema v2 stores one fixed size in its header and has no resize event, so the recorder writes the final size and every earlier, wider frame hard-wraps into garbage on replay. This is exactly what made PRD #339's clip unreadable (column 68 in a 60-column header). Re-record at one fixed size.
Re-timing ratio — clip N: re-timed 15.5s -> 24.5s (1.58x)A clip being stretched. The ratio is bounded by MAX_STRETCH, so anything wildly larger means a tunable (or CLIP_SPEED) was overridden into producing a slideshow.
Aspect — a segment more than ASPECT_TOLERANCE off the canvasA recording that will letterbox badly, with the percentage of the frame it will actually cover.

Still worth doing by eye before publishing: extract a frame and look at it (ffmpeg -ss <t> -i reel.mp4 -frames:v 1 -update 1 frame.png). No automated check substitutes for seeing the thing.

Local smoke test

A re-runnable smoke builds a reel from a tiny self-contained fixture (two hand-written .cast clips + a manifest under .claude/skills/demo-reel/tests/fixtures/) in stitch-only mode (no network, no credentials) and asserts the result with ffprobe: non-empty file, exactly one video stream at the expected resolution (a single stream proves there is no resolution/fps/pixfmt seam between segments), yuv420p, constant 30/1 fps, and a duration between the sum of the per-card holds and the engine's own upper bound on it (card holds + each clip's re-timing budget + a small per-clip allowance for agg's trailing hold). That upper bound is the regression guard for the 10.4x stretch above. It is local-only (never CI):

sh
task reel-smoke
# or directly:
.claude/skills/demo-reel/tests/smoke.sh

Privacy — uploads are PRIVATE by default, and that is a security boundary

upload.sh creates the video with privacyStatus: private, and reel.sh --publish passes no privacy flag at all, so the automated path can only ever produce a private video. upload.sh --privacy unlisted|public is the explicit escape hatch for a hand-run.

Why the default moved off unlisted: unlisted means anyone with the link can watch, and in this project's flow the link is written into the PR body and the changelog fragment, which flows into the public release notes. A reel clip is only eligible if the recorded run spun up a real agent, so every cast the reel stitches was written by a process holding live credentials. Uploading unlisted therefore put a credential-bearing recording on a publicly-reachable URL with no human between the two. Private keeps the same automation — the channel owner can always watch their own private videos, so an agent still uploads unattended and the link still goes in the PR — while making the human review a publication gate instead of a merge gate: flipping the video to unlisted before a release is a deliberate step somebody takes.

The video id survives a private → unlisted flip, so the link already in the PR and the changelog starts working with no re-upload and no link edit.

What private does not do. The upload has already happened; the bytes sit on Google's servers either way. Private contains a leak to the owner's own account. It does not undo one. And redaction upstream of this is a blocklist that can only remove values the harness registered — see docs/develop/e2e-lanes.md for its known gaps.

Verifying the upload path

The live YouTube upload cannot be a routine automated test, so it is verified by code review of upload.sh plus a one-time manual check: with the three YOUTUBE_* credentials exported, run

sh
.claude/skills/demo-reel/reel.sh some-manifest.json --out reel.mp4 --publish

and confirm it prints an https://youtu.be/<id> URL that opens a private video — signed in as the channel owner it plays normally and shows a Private badge; signed out, or as any account the owner has not deliberately shared it with, it is unavailable. That asymmetry is the point (see Privacy below). All hosting lives in upload.sh alone, so swapping hosts later does not touch the rest of the engine.

Failure behavior

  • Bad invocation (no manifest, unknown flag, --out without a value) prints usage to stderr and exits non-zero.
  • A missing manifest file, malformed JSON, or a manifest that breaks the contract above fails with a specific message and a non-zero exit.
  • A missing CLI (agg/ffmpeg/jq/curl) is a hard failure: it is reported by name in the pre-flight check before any work starts; the message points at docs/develop/demo-reel.md or to asking the agent, and does not embed setup steps.
  • Missing --publish credentials degrade gracefully: the reel is still stitched and the local MP4 is kept; only the upload is skipped, with a "reel is at <path>; could not publish (missing …)" note. Stitch-only runs never need credentials.
  • Runtime upload errors (expired/revoked token, exhausted quota, API disabled) are only knowable at upload time; upload.sh passes the API's raw error through rather than swallowing it.

© vfarcic, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 7 other files in .claude/skills/demo-reel of vfarcic/dot-agent-deck.

  • SKILL.md
  • reel.sh
  • retime.sh
  • tests/fixtures/clip-a.cast
  • tests/fixtures/clip-b.cast
  • tests/fixtures/manifest.json
  • tests/smoke.sh
  • upload.sh

Open the folder on GitHubat commit 9cc3e60

Compare with similar skills

Demo Reel next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Demo Reel compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Demo Reel this skillvfarcic/dot-agent-deck109—~5.2kAutomated safety check: NotesMIT
MarkitdownImCa0/just-laws78114 repos~3.2kAutomated safety check: NotesMIT
Banner Design Systemnextlevelbuilder/ui-ux-pro-max-skill135k1 repos~1.8kAutomated safety check: PassMIT
Agent ReachPanniantong/Agent-Reach95k—~1.4kAutomated safety check: PassMIT
Last30daysmvanhorn/last30days-skill64k—~7.9kAutomated safety check: NotesMIT
Baoyu URL To Markdownsdyckjq-lab/llm-wiki-skill2.5k2 repos~3.2kAutomated safety check: PassNone

Similar skills

  • Markitdown

    ImCa0/just-laws

    Convert files and office documents to Markdown. An agent skill from ImCa0/just-laws.

    781 GitHub starsUsed in 14 repos~3.2k tokens
    Documents & OfficeAuto-check: notes
  • Banner Design System

    nextlevelbuilder/ui-ux-pro-max-skill

    Walks through designing a banner for social media, ads, a website hero or print, from gathering requirements to building 2 or 3 art-direction options in HTML and CSS.

    135k GitHub starsUsed in 1 repo~1.8k tokens
    Frontend & DesignAuto-check passed
  • Agent Reach

    Panniantong/Agent-Reach

    Routes web research and platform lookups across 16 sites, including Twitter, Reddit, YouTube, Bilibili, Xiaohongshu and GitHub, through one command-line tool.

    95k GitHub stars~1.4k tokensUpdated 3 days ago
    Productivity & AutomationAuto-check passed
  • Last30days

    mvanhorn/last30days-skill

    Research what people actually say about any topic in the last 30 days.

    64k GitHub stars~7.9k tokensUpdated yesterday
    Research & ScienceAuto-check: notes
  • Baoyu URL To Markdown

    sdyckjq-lab/llm-wiki-skill

    Fetch any URL and convert to markdown using Chrome CDP. An agent skill from sdyckjq-lab/llm-wiki-skill.

    2.5k GitHub starsUsed in 2 repos~3.2k tokens
    Knowledge ManagementAuto-check passed
  • Google SEO APIs

    AgriciDaniel/claude-seo

    Pulls real Google data for SEO work: Search Console, PageSpeed Insights, CrUX field data, the Indexing API and GA4 organic traffic, through /seo google commands.

    19k GitHub starsUsed in 1 repo~4.2k tokens
    Marketing & SEOAuto-check passed

More from vfarcic/dot-agent-deck

All 24 skills in this repo
  • Dispatch Base

    vfarcic/dot-agent-deck

    Bring the base that every dispatched unit is cut from up to date before the first dot-agent-deck dispatch of a batch in this repo, and check the base dispatch reports afterwards.

    109 GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Dispatch Shape

    vfarcic/dot-agent-deck

    Choose the shape of a unit you are about to dispatch in this repo — one agent (--single) or a team (--orchestration '<name') — from divisibility criteria instead of asking, and report the shape you…

    109 GitHub stars~3k tokensUpdated today
    Auto-check passed
  • Docs Screenshots Review

    vfarcic/dot-agent-deck

    Check that a change to the user-facing docs covers both clients (the TUI and the desktop app) unless the feature exists in only one, and decide whether it needs a new or updated screenshot, then…

    109 GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Dot AI Request Dot AI Feature

    vfarcic/dot-agent-deck

    Generate a feature request prompt for another dot-ai project.

    109 GitHub stars~679 tokensUpdated today
    Auto-check passed
  • PR Create

    vfarcic/dot-agent-deck

    Take committed work from a branch to a verified pull request — push, open the PR, settle CI and the automated review, answer and resolve every finding, and hand off.

    109 GitHub stars~3.1k tokensUpdated today
    Auto-check passed
  • Publish Docs

    vfarcic/dot-agent-deck

    Publish the docs site to GHCR with a main-<sha tag and bump site/helm/values.yaml so Argo CD picks it up — without cutting a SemVer release.

    109 GitHub stars~1.7k tokensUpdated today
    Auto-check passed

Works with

Questions about Demo Reel

What does Demo Reel do?

Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube. Demo Reel is an agent skill from vfarcic/dot-agent-deck. Stitch a manifest of terminal recordings into one narrated MP4 (title/description card, then clip, repeated) and optionally upload it privately to YouTube.

When should I use Demo Reel?

Demo Reel fits situations like: asked to build a demo reel / narrated video from a set of asciinema casts.

How do I install Demo Reel in Claude Code?

Run `npx skills add vfarcic/dot-agent-deck --skill demo-reel -a claude-code`. Or copy the skill folder (.claude/skills/demo-reel in vfarcic/dot-agent-deck) into .claude/skills/demo-reel in your project. Claude Code loads it when a task matches its description.

How do I install Demo Reel in Codex?

Run `npx skills add vfarcic/dot-agent-deck --skill demo-reel -a codex`. Or copy the skill folder (.claude/skills/demo-reel in vfarcic/dot-agent-deck) into .agents/skills/demo-reel in your project. Codex loads it when a task matches its description.

Can I use Demo Reel in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add vfarcic/dot-agent-deck --skill demo-reel -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/demo-reel, .gemini/skills/demo-reel, .github/skills/demo-reel and .opencode/skills/demo-reel in your project.

What does Demo Reel need to run?

Going by SKILL.md and its folder, Demo Reel needs a shell for the scripts in its folder, the command-line tools its instructions call (ffmpeg) and credentials named YOUTUBE_CLIENT_SECRET and YOUTUBE_REFRESH_TOKEN. Our summary lists: A Bash shell; A credential in YOUTUBE_CLIENT_SECRET; A credential in YOUTUBE_REFRESH_TOKEN.

Does Demo Reel access the network?

SKILL.md names 1 domain. In commands or code: youtu.be; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Demo Reel safe to install?

Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Demo Reel use?

Demo Reel is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Demo Reel use?

About 5.2k tokens (SKILL.md is roughly 21k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Demo Reel?

Skills that share tags, products or a category with Demo Reel: Markitdown (ImCa0/just-laws, 781 stars), Banner Design System (nextlevelbuilder/ui-ux-pro-max-skill, 135k stars), Agent Reach (Panniantong/Agent-Reach, 95k stars) and Last30days (mvanhorn/last30days-skill, 64k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Demo Reel?

vfarcic (a GitHub user) maintains it in vfarcic/dot-agent-deck, which has 109 GitHub stars. The repository holds 23 skills in this directory. The repository was last updated on October 10, 2026.

Source: vfarcic/dot-agent-deck on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.