# Vocula for coding agents

Vocula makes the sound for the video or animation you are building: a voiceover with word timings,
narration fitted to a cut, or a whole soundtrack (voices, sound effects and music together). You get
files and timing; placing them is yours. The creator stays in charge: every job is a piece in their
Vocula account, where they can change any word or retake any line.

## Install the skills

- Claude Code: `claude plugin marketplace add honganai/vocula-agent-plugin` then `claude plugin install vocula@vocula`
- Any agent (Codex, Cursor, …): `npx skills add honganai/vocula-agent-plugin`

## The CLI

Zero install: `npx vocula@latest <command>`. One JSON object on stdout; progress and links on stderr.

```
vocula voices [--language en] [--gender female|male] [--mine]
vocula voiceover --lines lines.json --voice dacey-en-us --for hyperframes --out vocula/
vocula fit --video cut.mp4 --lines lines.json --cut as_is --with-video --out vocula/
vocula soundtrack --script script.md --direction "a bakery at dawn, warm, a little jingle" --out vocula/
vocula voice add --from clip.mp4 --own --consent "This is my own voice"
vocula quote --lines lines.json
vocula login · vocula quota · vocula status <job_id> --wait · vocula open <job_id> · vocula commands
```

`lines.json` is `[{"id":"hook","text":"…","who":"dacey-en-us","note":"warm, unhurried","max_s":2.5}]`.
`script.md` is one paragraph per line as `Who: text`, blank lines between parts.

## The four rules

1. Try before asking for anything. `voices`, `quote` and `commands` need no account. The first making
   command answers with a link; the creator opens it, connects the agent, and the same command runs again.
2. A wall (`status: "wall"`) is a step, not an error. It exits 0, says what to do next, and nothing was
   made or charged when it fired before work.
3. Claim only what the result says: durations are measured, the gate names every line delivered or
   failed, loudness is measured.
4. Talk to the creator in their words: minutes, voiceover, which line. Never file paths or seconds
   unless asked.

## What comes back

```
vocula/
  audio/<line-id>.wav      44.1 kHz mono, −16 LUFS / −1.5 dBTP per file (48 kHz for fit and nle)
  words.json               {lines:[{id,file,duration_s,words:[{id,text,start,end}]}]}   seconds, relative to each file
  captions.srt             sentence cues on the piece's clock
  captions.json            Remotion Caption[] (milliseconds)
  placement.json           [{id,file,start_s,duration_s,volume,track}]
  audio_meta.json          --for hyperframes: what HyperFrames' own audio step writes
  voiceover.json           --for remotion: {fps, lines:[{id,file,text,startFrame,durationInFrames,audioDelay}]}
  narration.wav, markers.csv, markers.edl, cut.xml, with-picture.mp4   fit jobs
  master.wav               soundtrack jobs
  result.json              lines, files, loudness, gate {requested, delivered, failed, overlaps}, charged_s, open_url
```

Duration-first by default: record at natural pace, then retime the picture to the voice. With a `slot`
or `max_s`, Vocula retakes to fit and reports `over_s` when it cannot. It never speeds audio up.

## The HTTP surface

Base `https://vocula.ai/v1`. A key in `Authorization: Bearer vk_…`, obtained only through a pairing link.

- `GET /voices`, `GET /voices/<handle>/sample.mp3`, `POST /quote`, `GET /commands` — no account
- `POST /link` → `{code, url}`; `GET /link/<code>` → `pending` or, once, `{state:"paired", key}`
- `GET /me` · `POST /jobs` · `GET /jobs/<id>?wait=120` · `POST /jobs/<id>/video` · `POST /jobs/<id>/cancel`
- `GET /voices/mine` · `POST /voices/mine?own=1&consent=1` · `DELETE /voices/mine/<id>`
- `GET /files/<token>` — a delivered file, 30 days, no key

Every body: `schema: "v1"` and `status: ok | wall | error`. Walls: `generation_requires_account`
(`action.url` is the pairing link), `minutes_exhausted` (`needed_s`, `balance_s`), `account_paused`,
`voice_not_found`, `consent_required`, `video_too_large`. Money is seconds in JSON and minutes to people.

Questions: contact@vocula.ai
