원클릭으로
kookr-demo-recording
How to record, verify, export, and publish the Kookr demo video with optional TTS narration audio
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
How to record, verify, export, and publish the Kookr demo video with optional TTS narration audio
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Make Codex CLI behave more like Claude Code for Kookr by preserving the known fork, branch, build, deploy, daily upstream sync, and live-verification workflow for Claude-compatible skills, agents, settings, hooks, and related UX.
Kookr-internal extension to rfc-iterative-review that captures append-only critic traces for later meta-analysis of RFC reviewer subagents.
Analyze an open question by casting 3-5 deliberately conflicting expert roles, running them in parallel and blind to each other, sharpening them in a debate round, attacking their consensus with a devil's advocate, then synthesizing a verdict that preserves disagreement instead of averaging it. Use for decisions, strategy, idea generation, hypothesis triage, experiment post-mortems, or any question where a single lens would return "it depends".
Iterative RFC drafting workflow — draft in worktree, run parallel critic subagents, incorporate feedback over N rounds, present to user before any action
How to create, structure, and launch Kookr playbook tasks — reusable agent task templates with dynamic sources and project identity
Build a Ralph-like sequential Kookr task chain where each task completes one independent unit, records durable state, and spawns the next task with the same continuation contract. Use for issue batches, queue drains, staged migrations, or other long runs that should proceed one task at a time without relying on conversation memory.
| name | kookr-demo-recording |
| description | How to record, verify, export, and publish the Kookr demo video with optional TTS narration audio |
| keywords | demo, video, recording, tts, text-to-speech, playwright, narration, audio, webm, mp4, vertical, shorts, gif, srt, subtitles, thumbnail, youtube, publish, regenerate demo, check mode |
| related | playwright-e2e-patterns, e2e-agent-testing |
When you need to generate, verify, or regenerate the Kookr demo video and its distribution formats, with or without voice narration.
The recording drives the real current frontend (built by pnpm build, served by the E2E test server), so the video always shows the current UI by construction. What drifts are the selectors and flows in the demo script. Before any recording — and after any significant frontend change — run:
pnpm demo:check
This replays the entire scenario headless with all holds capped to ~150ms, no TTS, no video, no exports (~1 min). It fails loudly on any selector or flow drift and ends with CHECK PASSED when the script is fully aligned with the current UI. Never record without a passing check.
The .env file in the repo root has HF_TOKEN and KOOKR_TTS=true. Copy it to the worktree if needed, then record with TTS:
cp $HOME/git/kookr/.env .env # if in a worktree
pnpm demo:record # reads .env automatically
Only record silent if TTS is genuinely unavailable (Docker down, no HF token).
KOOKR_TTS= pnpm demo:record
KOOKR_TTS_URL=http://localhost:8004 pnpm demo:record
The first narration line is selectable — everything else stays identical, so variants are cheap to regenerate and A/B test on social:
DEMO_HOOK=A pnpm demo:record # default: "Running five coding agents sounds like leverage…"
DEMO_HOOK=B pnpm demo:record # "Your AI agents are fast. Supervising them is the part that does not scale."
DEMO_HOOK=C pnpm demo:record # "This is what running five AI coding agents actually looks like…"
tts/docker-compose.yml), generates WAV clips for each narration line via POST /synthesizeFakeTerminalBackend + FakeTerminalBridge (no tmux needed)recordVideo, injects captions via DOM. The video opens directly on the cold-open terminal grid (pain first — social retention is decided in the first 3 seconds); the logo appears only on the closing CTA card.holdTime() ensures each caption holds long enough for the speech clip to finish (clip duration + 500ms padding)adelay filtersdemo/assets/music/ is looped, faded, and mixed at low volume under the narrationkookr-demo.srt is generated from the same narration timeline (upload with the video so YouTube can auto-translate captions)| File | Purpose |
|---|---|
demo/record.ts | Main recording script — scenario, captions, TTS orchestration, check mode |
demo/lib/timeline.ts | SRT builder + tracker-mark → cut-segment resolution |
demo/lib/exports.ts | ffmpeg export matrix (MP4/vertical/teaser/loop/GIF) + music bed |
demo/terminal-content.ts | Pre-scripted ANSI terminal output per agent |
demo/assets/music/ | Optional license-free music bed (first audio file is used) |
demo/output/ | Generated files (gitignored) |
tts/ | Pocket TTS Docker service (server.py, Dockerfile, docker-compose.yml) |
tts/voices/matilda.mp3 | Default narration voice (copied into the TTS image at build time) |
src/server/tts-manager.ts | TTS Docker lifecycle (start/stop/health) |
src/server/fake-terminal-bridge.ts | Streams pre-scripted content to xterm.js |
instant — dumps all content at once. Used for blocked/stopped agents (permission block, needs input). Terminal appears frozen.streaming — sends line-by-line at configurable speed. Used for healthy running agents. Conveys "this agent is busy."Defined in NARRATIONS object in demo/record.ts. Each key maps to a tracker.mark() call in the scenario. To change narration text, edit the NARRATIONS object. Opening hook lines live in HOOK_VARIANTS (selected via DEMO_HOOK).
Default: Matilda (/app/voices/matilda.mp3). Override with:
TTS_VOICE=alba pnpm demo:record # Built-in voice (no HF_TOKEN needed)
Built-in voices (no token): alba, marius, javert, jean, fantine, cosette, eponine, azelma
One recording produces every distribution format:
| File | Format | Channel |
|---|---|---|
kookr-demo.webm | 1080p WebM master (narration + optional music) | YouTube upload |
kookr-demo.srt | Subtitles from the narration timeline | Upload WITH the YouTube video → auto-translated captions worldwide |
kookr-demo.mp4 | 1080p H.264 + AAC | X / LinkedIn native upload (never link-only — native videos get far more reach) |
kookr-demo-4k.mp4 | 4K lanczos upscale | Release asset, high-DPI embeds |
kookr-demo-vertical.mp4 | 1080x1920 9:16, blur-padded | YouTube Shorts / Reels / TikTok |
kookr-demo-teaser.mp4 | ~30s cut (pain+hook → anomaly act → CTA) | Timeline teaser linking to the full video |
kookr-demo-loop.mp4 | 12s silent loop of the triage moment | Hero animation, social cards |
kookr-demo-loop.gif | Same loop as GIF | GitHub README autoplay |
kookr-demo-thumbnail.jpg | Designed thumbnail (headline over live UI) | YouTube custom thumbnail (<2MB) |
kookr-demo-screenshot.png | Screenshot at peak state | README / docs |
kookr-demo-triage.png | Screenshot during triage (terminal visible) | README / docs |
Drop one license-free track into demo/assets/music/ (mp3/wav/m4a/ogg/flac — first file alphabetically is used). It is looped to the video length, mixed at ~9% volume under the narration, faded in 2s / out 3s. No file → narration-only (a one-line log says so). Only applied to narrated recordings.
Mirrors the STT pattern exactly:
KOOKR_TTS=true → auto-start Docker container on server start, auto-stop on shutdownKOOKR_TTS_URL → use external service (skip Docker)src/server/tts-manager.ts (mirrors src/server/stt-manager.ts)Recording requires fonts-noto-color-emoji on Linux / Apple Color Emoji on macOS — verified by demo/lib/preflight.ts at startup.
The demo uses FakeTerminalBackend — no real agents run. This means features that depend on real infrastructure need fake data injected:
| Feature | Problem | Fix |
|---|---|---|
| Cost tracking | No transcripts → $0.00 | Use POST /api/test/set-spend to inject per-task token usage and lifetime spend |
| Terminal output | No tmux sessions | Use POST /api/test/set-terminal-content with pre-scripted ANSI content |
| Project sidebar | No git remotes | Use POST /api/test/set-project-id + set-project-config |
| GitHub PRs | No gh CLI polling | Use POST /api/test/broadcast-github |
| AI suggestions | No LLM call in test mode | Use POST /api/test/broadcast-suggestion |
| Playbooks | No .kookr/playbooks/ on disk | Use POST /api/test/broadcast-playbooks |
| Completion digest | No real events to summarize | Use POST /api/test/set-completion-digest/:taskId |
Rule: every caption claim must have corresponding injected data. If you say "cost tracked in real time", the TopBar must show a nonzero dollar amount.
?onboarding=0 URL param (version-proof) + the kookr:onboarding:seen-v2 localStorage key. If the tour overlay intercepts clicks, the storage key version bumped — update both.selectFindingByText retries once.invalid_cwd. The e2e test server no-ops the check (#871), but seeded agents use real temp dirs ($TMPDIR/kookr-demo-cwd/..., created in record()) so the demo never depends on that no-op staying in place..detail-agent-provider resolves but is hidden until the .detail-meta-menu > summary is clicked. Open the popover on screen before zooming on the Codex badge.set-terminal-content on an already-open terminal does nothing visible. To show an agent "resuming", set the new streaming content first, then (re)select the task so a fresh terminal connection picks it up..env carries real Telegram credentials: the demo server is forked with KOOKR_REMOTE_CHAT_DISABLED=1, otherwise injected demo alerts send actual Telegram notifications mid-recording.route.fulfill() on the document breaks the page's WebSocket: Chromium's Local Network Access checks block ws://127.0.0.1 from a fulfilled (provenance-less) document with ERR_BLOCKED_BY_LOCAL_NETWORK_ACCESS_CHECKS. The recorder launches Chromium with --disable-features=LocalNetworkAccessChecks. Symptom if it regresses: the dashboard renders but stays empty (no tasks, no findings) while API seeding succeeds.Playbooks in the demo must feel like real workflows a developer would repeat:
Include at least one playbook with a select dropdown parameter so the viewer sees the parameter form is rich, not just text inputs.
When demonstrating interactive UI (snooze dialog, launch dialog, playbook parameters):
These came out of a panel of simulated first-time viewers (skeptic, eng manager, newcomer, power user) reviewing the actual frames + narration:
PreToolUse so the agent visibly resumes. "Send" must not look like it goes into the void.video_end tracker mark; the published video is trimmed there, so the overlay never appears in footage.Round 2 (second fresh-eyes panel: skeptic, retention editor, OSS-maintainer ICP, non-native/muted viewer):
zoomTo/zoomReset) for anything that must be readable on a phone: permission card + actions, AI reply drafts, PR card, completion digest, the TopBar cost. A 1080p dashboard wide-shot is ~8px text on mobile. zoomTo waits for its selector, so check mode catches zoom-target drift.setSpend at act transitions, final tick lands exactly on the number the narration quotes). A static counter reads as mocked data — the skeptic persona called a never-changing "$1.47" the single biggest credibility hit.pulseHighlight) interactive elements before clicking them (project chips, GitHub tab) — muted viewers need to see WHERE the interaction happens, narration can't carry it.After recording, verify each of these before committing:
[tts] Generated N/N clips in output. If any failed, fix before shipping.[export] Artifact summary: block at the end of the run must list every file with no MISSING entries.kookr-demo.srt — cue times must roughly match when each caption appears in the video.The live video is YouTube DHZrO8T_6Xg, linked from the root README.md (thumbnail image + link). When shipping a new version:
kookr-demo.webm (or the 4K MP4), plus kookr-demo.srt as a subtitle track (enables auto-translated captions worldwide), plus kookr-demo-thumbnail.jpg as the custom thumbnail. Title pattern: "Kookr — supervise 5 AI coding agents from one attention queue".img URL and the watch link.kookr-demo-4k.mp4, kookr-demo.mp4, and kookr-demo-vertical.mp4 to the next GitHub release (per demo/README.md, long-form media lives on releases, not in the repo).kookr-demo-vertical.mp4 with the repo URL in the description.kookr-demo.mp4 (or the teaser with a link to the full video). Never post a bare YouTube link — native uploads get materially more reach.DEMO_HOOK variant used, so the next regeneration knows what is live.pnpm demo:check fails — fix the scenario, then re-record| Issue | Fix |
|---|---|
| "Voice load failed" | Need HF_TOKEN in .env for voice cloning voices. Or use a built-in voice. |
| Docker build timeout | First build installs PyTorch+CUDA (~6GB). Subsequent builds use cache. |
| ffmpeg not found | Install ffmpeg: sudo apt install ffmpeg |
| No audio in output | Check that [tts] Generated N/N clips shows in output. If 0, TTS failed. |
| Broken emoji boxes | Install fonts-noto-color-emoji (Linux) and run fc-cache -fv. Preflight will fail fast if the font is missing. |
| $0.00 in TopBar | Inject fake spend data via /api/test/set-spend |
| Snooze/complete task vanishes | Wait for the snoozed/completed section to render after the action |
| Onboarding overlay blocks clicks | Storage key version bumped — see "UI behaviors that have bitten the scenario" |
| Export job FAILED in summary | Re-run just the exports by calling the function from demo/lib/exports.ts against the existing kookr-demo.webm |