Praeko Studio: make videos with your agent
Praeko Studio makes short (9:16) and long (16:9) videos from a script: voice, word-by-word captions, scenes, a cover and the texts for each network. You drive it with your own coding agent, on your machine: the agent writes the script and episode.yaml, runs the commands and, only after your yes, publishes through Praeko. Voice, rendering and the agent are on you; Studio never calls a language model and none of your scripts leave the machine until you publish.
Requirements
| Item | Detail |
|---|---|
| Node | 22 or newer. |
| ffmpeg e ffprobe | On the PATH. macOS: brew install ffmpeg; Debian and Ubuntu: sudo apt install ffmpeg. |
| Chrome | Remotion downloads *Chrome Headless Shell* by itself on the first render (internet needed then; about 570 MB on disk, measured on macOS). Or use an installed Chrome through CHROME_PATH. |
| Fonts | The template uses system fonts (Arial Black, Menlo). If missing, doctor warns; swap them in brand.json for fonts that exist on your systems. |
| Systems | macOS and Linux. Windows is best effort and untested. |
| Terminal | The agent needs a terminal (shell) to render: it is what runs ffmpeg, Remotion and the Studio commands. Without a terminal (for example, Claude Desktop without a shell), use the local Studio MCP server (@praeko/studio-mcp); the remote MCP server only publishes and reads insights, it does not render video. |
| Your agent | Claude Code, Codex, Gemini CLI, Cursor, opencode, Cline or Windsurf, with your own subscription or key. Praeko neither bills nor brokers the agent. |
Install
npm install -g @praeko/studioyarn global add @praeko/studiopnpm add -g @praeko/studiobun add -g @praeko/studionpx @praeko/studio doctor
npx @praeko/studio init my-channelThe command is praeko-studio, and also praeko studio … when @praeko/cli is installed: it hands over to Studio, looking in the project, next to the CLI, in the global install and on the PATH.
Licenses: read before your first render
| Component | License |
|---|---|
@praeko/studio, studio-core, studio-kit |
MIT |
Remotion (remotion, @remotion/cli) |
Remotion License (not MIT); you install it |
HyperFrames (--engine hyperframes, optional) |
Apache-2.0 |
| ffmpeg, Chrome | Their own terms; Studio does not redistribute them |
| VoiceStudio's OmniVoice model (optional local voice) | CC-BY-NC: non-commercial; do not use for monetized content |
Remotion is the default engine for videos and covers; with --engine hyperframes the video and the cover are rendered by HyperFrames and nothing from Remotion is used. Full text and sources: praeko studio docs licenses (the package's LICENSES.md); praeko studio licenses --accept records that you read it.
Your first video in 10 minutes
Check the environment
praeko-studio doctorShows Node, ffmpeg, Chrome, fonts, whether keys exist (never the value), the ElevenLabs voice accounts (balance and renewal date when the key can read it; the final voice and which accounts have its id; it warns if two accounts show the same balance), the network and the licenses, with a one-line fix per item. With --offline it makes no network call and shows configuration only.
Create the project
praeko-studio init my-channel --name "My Channel" --agent claude
cd my-channelCreates brand.json, src/, episodes/, the sounds and the instructions for your agent (--agent claude,codex,gemini,cursor,opencode,cline,windsurf or all), and runs npm install. In a terminal it first runs a short interview (name, audience, tone of voice, colors, font, up to 3 references) and writes brief.md and a draft playbook.md, which your agent reads before the first script; Studio does not watch the references, your agent analyzes them. Without a terminal (or with --yes) nothing is asked. Packages come from npm by version, with no file:.
Ask your agent for the video
Open your agent in the project folder and paste:
Make a 40-second Short about <TOPIC> in this Praeko Studio project.
Read the project instructions and run `praeko studio docs episode-yaml` before writing the YAML.
Use the draft voice, show me the script and scenes to approve before spending any voice credit,
run check and contact-sheet, and do not publish anything unless I ask.Draft voice, checks and render
praeko-studio new my-first --title "My first video"
praeko-studio voice my-first --quality draft
praeko-studio check my-first
praeko-studio render my-first --scale 0.5
praeko-studio contact-sheet my-first
praeko-studio cover my-first
praeko-studio package my-firstThe agent runs these for you. The draft voice is estimated and silent (free, no network) and is for laying out scenes; check warns until there is a real voice. For the final voice, --quality final uses your ElevenLabs account.
Simulate publishing
echo $PRAEKO_KEY | praeko-studio schedule --via praeko --key
praeko-studio schedule my-first --when "20/12 17:30" --via praekoWithout --send the command only reads your channels and shows what it would do. See Publish.
Commands
All start with praeko studio (or praeko-studio). praeko studio --help lists the same.
| Command | Does |
|---|---|
doctor [--json] [--offline] |
Checks the environment and shows the license notice. |
licenses [--accept] |
The license notice; --accept records that you read it. |
skill install [--agent …] [--lang en|pt] |
Writes the Studio instructions in your agent's format. |
docs [topic] |
Docs for the installed version: episode-yaml, long-yaml, voice, publish, hyperframes, licenses. |
init <folder> |
Creates a project (--name, --handle, --agent, --lang, --no-install; --dev <studio> for contributors). In a terminal it runs the brand interview (Enter skips each question); with --yes or without a terminal it asks nothing and imports colors and font from ../brand/build/tokens.json (or ../brand/tokens.json) when present, or from the folder given in --brand; flags win over the tokens and the output says what was imported. Answers by flag: --about, --audience, --tone, --accent, --background, --font, --brand <folder>, --reference (up to 3, with --reference-note), --voice-alias, --voice-provider. |
brief [--only …] |
Reopens the interview in an existing project (only the chosen answers) and rewrites brief.md; keeps brief.md.bak and never overwrites a playbook.md you edited (writes playbook.md.new). |
new <slug> [--long | --image] |
Creates an episode (--title) and registers it in src/Root.tsx. --image creates a photo post (format: image, one slide, no voice or video). |
voice <slug> --quality draft|final|local |
Generates the voice and per-word timings. voice balance, voices, account, config key manage accounts. |
compile <slug> |
Reads episode.yaml, checks anchors and overlap, writes episode.spec.json. |
cut <long> <slug> --from … --to … |
A vertical Short sliced from a long video's voice. |
preview [slug] |
Opens Remotion Studio (or the HyperFrames preview). |
render <slug> [--scale 0.5] [--engine remotion|hyperframes] |
Renders to out/<slug>.mp4. |
cover <slug> |
Renders the cover (out/<slug>-cover.png). |
slides <slug> |
Renders an image post to out/<slug>-slide-01.jpg: 1080x1350 (4:5), sRGB JPEG, Remotion only. For now it goes only to Instagram (schedule --via praeko); the format is in praeko studio docs image. |
contact-sheet <slug> [--n 12] |
A frame mosaic for you (and the agent) to look at. |
check <slug> |
Script, voice, publishing, AI disclosure and, with a video, duration, loudness and blank frames. |
package <slug> |
Writes texts.md (YouTube, Instagram, TikTok, UTM) and checks limits. |
schedule <slug> --when … --via praeko [--send] |
Schedules through Praeko; without --send it only simulates. |
post, queue, account <network> |
Advanced: direct publishing with your own credentials for each network. queue install is macOS only. |
migrate [--dry-run] |
Converts a Studio 0.1.x project (Portuguese names) to the English layout, with a backup in .studio-backup/. |
help |
Shows the command list (--lang pt translates the messages). |
The project
my-channel/
brand.json # colors, fonts, handle, voice, links, hashtags
voices.json # (optional) your voice; never keys
src/ # index.ts, Root.tsx, brand.ts (Root registers the episodes)
public/ # sfx/, cover/avatar.png, audio/ (generated voice)
episodes/<slug>/
script.txt # the spoken text
episode.yaml # the scenes, declarative
scenes.tsx # TSX pieces (cover and what YAML cannot express)
publication.json # texts for each network, hashtags, ai.synthetic
out/ # rendered videos and covers{
"name": "My Channel",
"handle": "@mychannel",
"avatar": "cover/avatar.png",
"colors": { "background": "#14110f", "accent": "#f4b942", "text": "#f3ece0" },
"fonts": { "title": "'Arial Black', system-ui, sans-serif", "mono": "Menlo, monospace" },
"links": { "main": "https://example.com/" },
"voice": "draft-silent",
"pronunciation": { "example.com": "example dot com" },
"bannedNames": [],
"publishing": { "provider": "praeko", "hashtags": { "allowed": [], "banned": [] } }
}episode.yaml is declarative: each item ties to a spoken phrase with when: "phrase", and praeko studio compile checks it. What YAML cannot express becomes a piece in scenes.tsx, built with the @praeko/studio-kit pieces (panel, box, line, bubble, code, window, phone, frame). Rendering is a pure function of the compiled episode and the project files.
id: MyVideo
duration: 14
caption: 80
voice: audio/MyVideo.mp3
background: ["My video"]
outro: { start: 10, cta: FOLLOW THE PROFILE }
cover: { id: CoverMyVideo, component: CoverMyVideo }
scenes:
- start: 0
title: THE PROBLEM
label: PROBLEM
items:
- { type: big, at: 0.2, color: accent, size: 92, text: "The cache took the deploy down" }
- { type: box, when: "deploy", text: "cleared the cache" }Full format: praeko studio docs episode-yaml, praeko studio docs long-yaml and, for a photo post, praeko studio docs image.
Image posts (a photo)
praeko studio new <slug> --image creates an image piece: the same publication.json, check, package and upload as a video, but with no script, voice or video. Its episode.yaml has format: image and one slide (several slides would be a carousel, which arrives in a later phase) that reuses the items of a cover and carries an alternative text (alt, required, up to 1000 characters). praeko studio slides <slug> renders out/<slug>-slide-01.jpg at 1080x1350, sRGB JPEG (Remotion only). package writes the images and the alt into publication.json and a texts.md with only the Instagram caption. Only Instagram takes a photo for now (YouTube has no image posts; TikTok photo mode is a later phase): praeko studio schedule <slug> --via praeko uploads the photo as media of type: image and creates the post with kind: image. The alt goes to Instagram when Praeko publishes through Meta; through Buffer it is ignored and the item warns alt_ignored.
Keys and costs: bring your own
| What | Who pays | Where the key lives |
|---|---|---|
| Coding agent | You (your subscription or key) | In the agent itself |
| Final voice (ElevenLabs) | You, on your account | ELEVENLABS_API_KEY variable, the macOS keychain or ~/.config/praeko/secrets.json (mode 600) |
| Rendering | You (your machine) | - |
| Publishing through Praeko | Your Praeko plan | PRAEKO_KEY or praeko studio schedule --via praeko --key (the same key as the praeko CLI) |
echo $ELEVENLABS_API_KEY | praeko-studio voice config key elevenlabs/principal
praeko-studio voice account add principal --voice my-voice --voice-id <YOUR_VOICE_ID>praeko-studio voice account list
praeko-studio voice account add backup --from-env ELEVENLABS_API_KEY_2 --dry-run # only checks the key and shows the plan, stores nothing
praeko-studio voice account add backup --from-env ELEVENLABS_API_KEY_2 # stores the key in the keychain and the voice in voices.jsonWithout --from-env, the command asks for the key in the terminal (hidden) or reads it from standard input. --voice gives the voice a nickname and --voice-id sets the id; without them the command looks for your voice clone in the account. With more than one account, Studio picks by remaining balance and switches account when one runs out (--no-failover turns it off).
The key never goes into the project, git, logs or the chat with your agent. Use only your own voice or one you are authorized to use. Details: praeko studio docs voice.
Publish through Praeko
Studio never publishes on its own. Two ways, both only after your yes:
- CLI:
praeko studio schedule <slug> --via praeko --when "dd/mm hh:mm"simulates; with--sendit uploads the video and really schedules. YouTube goes up private and scheduled; TikTok goes as a draft. - Praeko MCP: an agent with a shell uploads the local file with
create_media_upload(one step; it returns thecurl), finishes withcomplete_media_uploadand creates the post withcreate_postorschedule_postin two steps: the first call returns only the preview and aconfirmation_code; the agent shows you the whole preview and repeats the call withconfirmonly after your yes. See MCP server.
Instructions for your agent
praeko-studio skill install --agent claude,codex,gemini,cursor,opencode,cline,windsurf --lang en| Agent | File written in the project |
|---|---|
| Claude Code | .claude/skills/praeko-studio/SKILL.md + CLAUDE.md |
| Codex, opencode | AGENTS.md |
| Gemini CLI | GEMINI.md |
| Cursor | .cursor/rules/praeko-studio.mdc |
| Cline | .clinerules/praeko-studio.md |
| Windsurf | .windsurf/rules/praeko-studio.md |
The text carries the video workflow, the local file upload, the two-step rule and the AI disclosure. In shared files (AGENTS.md, CLAUDE.md, GEMINI.md) Studio writes only a delimited block and keeps the rest. Each agent's formats change over time: check your agent's documentation.
Troubleshooting
| Symptom | What to do |
|---|---|
ffmpeg not found |
Install it (brew install ffmpeg or sudo apt install ffmpeg) and run praeko studio doctor. |
| The first render is slow or fails on network | Remotion is downloading Chrome Headless Shell. With internet, retry. Offline, install Chrome and set CHROME_PATH. |
| Text looks different or wraps oddly | A font from brand.json is missing. doctor shows which; install it or switch to an open font. |
| Linux: no key vault | The macOS vault (security) exists only on macOS. On Linux use ELEVENLABS_API_KEY, PRAEKO_KEY or the ~/.config/praeko/secrets.json file (mode 600). |
| Windows | Untested. Prefer environment variables for keys and report anything that fails. |
praeko studio says it cannot find Studio |
Install @praeko/studio (in the project or globally) or run it with npx @praeko/studio. |
check warns the voice is estimated |
Expected with the draft. Generate --quality final (with your key) before publishing. |
| Studio 0.1.x project (Portuguese names) | Run praeko studio migrate --dry-run and then praeko studio migrate: it renames files and keys, with a backup in .studio-backup/. |
AI-generated content and compliance
Realistic synthetic voice, or generated image and video that looks real, requires the altered or synthetic content label on YouTube, "AI info" on Instagram and the AI-generated content label on TikTok. Fill "ai": { "synthetic": true } in publication.json: check and package warn when it is missing. In Studio's direct publishing YouTube receives the field (containsSyntheticMedia); through Praeko and on Instagram and TikTok you set the label in the network's app before publishing, because Praeko's public API does not carry this field yet. Each network's rules change: check the current policy.