# Praeko Studio: make videos with your agent

> Install Praeko Studio, make your first video in 10 minutes with your coding agent (Claude Code, Codex, Gemini CLI, Cursor, opencode), see the commands, the project, keys, licenses (Remotion is not MIT) and how to publish through Praeko.

Source: https://praeko.app/docs/en/studio

Node 22 or newer · macOS and Linux · Remotion is not MIT

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.

> **Want the agent to do almost everything?** The [Get started with your AI agent](https://praeko.app/docs/en/get-started-with-agent) guide has the prompt to paste into an empty folder, what only you do and the first video.

## 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](https://praeko.app/docs/en/studio/mcp) (`@praeko/studio-mcp`); the remote [MCP server](https://praeko.app/docs/en/mcp) 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**

```bash
npm install -g @praeko/studio
```

**yarn**

```bash
yarn global add @praeko/studio
```

**pnpm**

```bash
pnpm add -g @praeko/studio
```

**bun**

```bash
bun add -g @praeko/studio
```

**Without installing**

```bash
npx @praeko/studio doctor
npx @praeko/studio init my-channel
```

The command is `praeko-studio`, and also `praeko studio …` when [`@praeko/cli`](https://praeko.app/docs/en/sdk) 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

> **Remotion is not MIT** Praeko Studio's own code is MIT. **Remotion**, the default engine (for videos and covers), is *source-available*: **free for individuals, non-profits and companies of up to 3 employees**; companies of 4 or more people need the **Company License** ([remotion.pro/license](https://www.remotion.pro/license)). You install and run Remotion, so the license is yours. Remotion also sells plans for programmatic or agent-driven rendering, and their FAQ does not say whether a local agent counts: ask them before using at scale. We do not promise "free forever".

| 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

### 1. Check the environment

**bash**

```bash
praeko-studio doctor
```

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

### 2. Create the project

**bash**

```bash
praeko-studio init my-channel --name "My Channel" --agent claude
cd my-channel
```

Creates `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:`.

### 3. Ask your agent for the video

Open your agent **in the project folder** and paste:

**Prompt for the agent**

```text
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.
```

### 4. Draft voice, checks and render

**bash**

```bash
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-first
```

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

### 5. Simulate publishing

**bash**

```bash
echo $PRAEKO_KEY | praeko-studio schedule --via praeko --key
praeko-studio schedule my-first --when "20/12 17:30" --via praeko
```

Without `--send` the command only reads your channels and shows what it would do. See [Publish](#publicar).

## 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

**Layout**

```text
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
```

**brand.json**

```json
{
  "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.

**episode.yaml**

```yaml
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) |

**Store the voice key**

```bash
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>
```

**Add another voice account (or just check)**

```bash
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.json
```

Without `--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 `--send` it 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 the `curl`), finishes with `complete_media_upload` and creates the post with `create_post` or `schedule_post` in **two steps**: the first call returns only the preview and a `confirmation_code`; the agent shows you the whole preview and repeats the call with `confirm` only after your yes. See [MCP server](https://praeko.app/docs/en/mcp).

## Instructions for your agent

**bash**

```bash
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.

> **Privacy** Scripts, voices and keys stay on your machine. Praeko receives only the video, cover and texts you choose to publish. There is no telemetry.
