This is the exact file your agent reads. Install it for Claude Code with one command, then mint a token at the dashboard:
mkdir -p ~/.claude/skills/tmpvid && curl -fsSL https://tmpvid.com/skill.md -o ~/.claude/skills/tmpvid/SKILL.mdtmpvid — record a demo of your branch, embed it in the PR
The job: produce a short visual recording of the thing you just built or fixed, and put it in the pull request so reviewers see it working instead of reading claims. GitHub's API has no way to attach media to a PR, and externally-hosted video never plays inline in GitHub markdown (only images do, via camo). So the pattern is: record → trim → GIF for inline play + full video for the click-through → embed the GIF linked to the video. Everything auto-expires in 7 days (30 max).
1. What a good demo looks like
Before touching tools, decide the slice worth showing:
- One flow, 15–30 seconds. "Clicking checkout applies the discount" — not a tour of the app. Reviewers scrub past anything longer.
- Start clean, end on the proof. Begin at the page before the action, finish on the state that demonstrates the change (success banner, new UI, fixed behavior).
- No dead time. Cut logins, page loads, and typing — either drive the app fast programmatically or trim the footage after.
If the change has no visual surface (pure backend, refactor), a demo may be the wrong artifact — say so instead of recording a terminal.
2. Check the token
You need TMPVID_TOKEN in the environment. If it's missing, stop and tell the human:
Mint an agent token at https://tmpvid.com/dashboard (one-time), then set TMPVID_TOKEN in this environment.Do NOT attempt to register or mint a token yourself — there is no agent-side registration.
3. Capture the recording
Use whatever recorder fits the situation; you need an mp4/webm at the end.
Web app — Playwright is the usual tool. Run the app, then drive the flow with video recording on:
const context = await browser.newContext({ recordVideo: { dir: "videos/" } });
const page = await context.newPage();
// ...drive the flow fast: page.goto(), page.click(), expect() the proof state...
await context.close(); // video is finalized on close → videos/*.webmTips: set a deterministic viewport (e.g. 1280×720), prefer getByRole clicks over real-time typing (instant input = no dead footage), and pre-seed auth (state/storage) instead of recording a login.
No browser involved? Record whatever shows the change — a terminal session (asciinema → gif via agg), a simulator, a screenshot sequence. If nothing moves, take one good screenshot of the result and skip to §5 with it — a static image embeds identically to a GIF.
4. Trim and convert to GIF
Raw recordings are almost always too long and too large. Trim to the interesting slice, then convert:
# trim: start 2s in, keep 18s (adjust to your footage — see §1)
ffmpeg -i recording.webm -ss 2 -t 18 -c copy trimmed.webm
# convert to GIF, 960px wide, 12fps
ffmpeg -i trimmed.webm -vf "fps=12,scale=960:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=bayer" -loop 0 demo.gifThe GIF must be under 5MB (GitHub's image proxy refuses larger, and tmpvid rejects images over 5MB anyway). If it's bigger, drop fps to 8, then scale to 640, then shorten -t. Keep the trimmed video file too — it's the click-through target and may be up to 25MB.
No ffmpeg? Fall back to a PNG screenshot as the inline image (§3).
5. Upload
Raw binary body, metadata in headers. Response is JSON. Upload both files: the GIF and the video.
curl -sS -T demo.gif \
-H "Authorization: Bearer $TMPVID_TOKEN" \
-H "X-Tmpvid-Title: checkout flow test" \
-H "X-Tmpvid-Repo: owner/repo" \
-H "X-Tmpvid-Pr: 123" \
https://tmpvid.com/v1/recordingsResponse (fields shown are the complete shape; you mainly need url and page_url):
{
"id": "…",
"url": "https://tmpvid.dev/v/….gif",
"page_url": "https://tmpvid.com/v/…",
"kind": "gif",
"size_bytes": 123456,
"status": "live",
"views": 0,
"repo": "owner/repo",
"pr": 123,
"title": "checkout flow test",
"created_at": "…",
"expires_at": "…",
"deduplicated": false
}Metadata constraints (validated, 400 on violation): title ≤200 chars, repo must look like owner/name, pr an integer 1–999999. Control/bidi/zero-width characters are rejected everywhere.
6. Embed in the PR
Use the **GIF's url as the image and the video's url** (the raw tmpvid.dev link) as the link target:
[](https://tmpvid.dev/v/<video-id>.mp4)Reviewers see the GIF playing inline; clicking opens the raw video URL, which browsers play directly in the built-in player (no page, no sign-in). If you only made a screenshot, use it as the image and the video's url as the link target.
The page_url field (tmpvid.com/v/<id>) is the owner-only provenance page — agent, repo/PR, views. It exists for your human's dashboard and for abuse moderation; anyone else gets a private-recording notice. Don't send reviewers there.
7. Errors
Failures return {"error": {"code": "…", "message": "…"}} (plus retry_after seconds on 429). Handle:
unauthorized(401) — token missing/invalid. CheckTMPVID_TOKENis set and complete. Do NOT tell the human to re-mint (that'stoken_revoked).token_revoked(401) — tell the human to re-mint at tmpvid.com/dashboard.empty_body/invalid_metadata(400) — fix the request; see constraints above.invalid_body/invalid_expiry(400, PATCH/DELETE) — malformed JSON, past date, or beyond the 30-day cap. The cap is measured **from the recording'screated_at**, not from now — computecreated_at + 30d, notnow + 30d.hash_blocked(403) — these exact bytes are banned. Do not retry the same bytes.not_found(404) — no such id (or not yours).already_expired(409, PATCH/DELETE) — the recording is no longer live; expiry is one-way.too_large(413) — video >25MB or image >5MB; shrink and retry.unsupported_media_type(415) — not mp4/webm/gif/png/jpg; check the file.quota_exceeded(429) — daily cap hit; waitretry_afterseconds (UTC midnight).commit_failed/upload_failed(500) — infrastructure failure, safe to retry (identical bytes dedupe cleanly).deduplicated: truein a 200 — the same bytes were already uploaded; use the returned URLs, don't re-upload.
Reference
- Check status:
curl -sS -H "Authorization: Bearer $TMPVID_TOKEN" https://tmpvid.com/v1/recordings/<id>— trustexpires_at, notstatus(a row can read"live"just past expiry; expiry is enforced at request time). - Extend expiry (≤ created_at + 30 days):
curl -X PATCH -H "Authorization: Bearer $TMPVID_TOKEN" -H "Content-Type: application/json" -d '{"expires_at":"<iso8601>"}' https://tmpvid.com/v1/recordings/<id> - Delete early:
curl -X DELETE -H "Authorization: Bearer $TMPVID_TOKEN" https://tmpvid.com/v1/recordings/<id>
/skill.md — the raw file your agent reads. · contact@tmpvid.com