# Music Room (/docs/gateway/music-room)

codai Studio Music Room — a team of role agents writes, plays, sings and mixes a song that sounds played by people, with three approval gates, a monthly plan quota and an editable audio creative.

The **Music Room** is a team of role agents that produces one song together: a producer plans it, a composer and a lyricist write it, an arranger builds the form, session players write their parts on real sampled instruments, a vocal producer adds the vocals, mix and mastering engineers finish it, a critic listens, and a rights check compares the melody against a reference corpus. The result is a normal [audio creative](./audio-creatives.mdx): every note any agent wrote is an editable op with undo, and you can take over in the multitrack editor at any time.

| Method | Path | Result |
| --- | --- | --- |
| `POST` | `/v1/studio/music-room` | Start a song (202, `Idempotency-Key` honoured) |
| `GET` | `/v1/studio/music-room` | Your songs, newest first (`?limit` 1–100, `?before` ISO date) |
| `GET` | `/v1/studio/music-room/quota` | `{ plan, included, used, remaining, period_end }` |
| `GET` | `/v1/studio/music-room/{id}` | The song; reading it advances the workflow |
| `POST` | `/v1/studio/music-room/{id}/choose` | Answer the open gate |
| `POST` | `/v1/studio/music-room/{id}/direct` | Talk to one player (202, `Idempotency-Key` honoured) |

## How a song is made [#how-a-song-is-made]

```
brief ─► plan ─► [gate 1: choose a plan variant] ─► compose ─► lyrics ─► arrange ─► parts
      ─► humanise ─► demo render ─► [gate 2: approve the demo or direct a player]
      ─► vocals ─► mix ─► master ─► critique (at most 2 rounds of fixes) ─► [gate 3: approve the final mix] ─► ready
```

Agents never write audio directly. They write symbolic parts on a beat grid; deterministic code humanises timing and dynamics per player; `codai-studio-media` renders the stems with sampled instruments; ACE-Step sings the vocals over a rendered guide, checked by speech recognition and repaired syllable by syllable. The critic scores groove, harmony, melody, arrangement, mix, humanness and genre fit and sends targeted fixes back to the players at most twice. `robot_score` (0 human … 1 robotic) is a symbolic measure of the usual "AI tells", and `copy_risk` reports melody similarity to known tunes.

## Starting a song [#starting-a-song]

```bash
curl https://ai.codai.ro/v1/studio/music-room \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: song-42" \
  -d '{
    "brief": "a cheerful wedding song about two friends who finally meet again",
    "language": "ro",
    "genre": "hora",
    "duration_seconds": 150,
    "vocals": true
  }'
```

| Field | Default | Notes |
| --- | --- | --- |
| `brief` | required | 10–2000 characters: occasion, mood, story, audience; no artist names |
| `language` | `ro` | `ro` or `en` — the language of the lyrics |
| `genre` | the producer picks | A genre pack id: `pop`, `jingle`, `rock`, `indie`, `hiphop`, `trap`, `cinematic`, `lofi`, `ballad`, `hora`, `sarba`, `doina`, `colind`, `lautareasca`, `manele`, `pop_folk_ro`, `fanfara`, `cocek`, `kolo`… |
| `duration_seconds` | — | 6–240 (four minutes at most) |
| `vocals` | `true` | `false` for an instrumental |
| `timbre` | chosen for the genre | A vocal timbre id |
| `voice_passport_id` | — | Sing with your own voice (beta): one of your custom voices with an active singing consent. See [Voice passport](#voice-passport-beta) |
| `instruments` | — | Instrument ids the band must use (`drums.kit_rock`, `balkan.accordion`…) |
| `auto` | `false` | Skip the three gates (plan variant 0, demo and final approved) |
| `budget_micro_usd` | `10000000` | Cap for one song beyond the quota, at most `20000000` ($20) |
| `title` | — | Up to 200 characters |

The answer is `202` with the song (`object: "studio.music_room"`). Poll `GET /v1/studio/music-room/{id}` every 20–60 seconds; the background sweeper also moves the song forward when nobody polls.

### Voice passport (beta) [#voice-passport-beta]

Your own custom voice can sing your songs once you give a **separate, revocable singing consent** for it: in the hub voice card "Singing (beta)" you read the singing statement aloud and record a short sung sample (the same in-app liveness check as when the voice was created), which calls `POST /v1/studio/voices/{id}/singing-consent`. `DELETE /v1/studio/voices/{id}/singing-consent` revokes only the singing purpose; deleting the voice revokes everything. The vocal producer passes your sung sample to ACE-Step as a timbre reference, so the result **approximates your timbre; it is not a faithful clone**. Available only where voice cloning is enabled for your account.

`warnings` tells you what happened: `voice_passport_beta` (sung with your voice), `voice_passport_needs_singing_consent` (no active singing consent, or revoked during the song), `voice_passport_not_found` (not one of your active voices), `voice_passport_unavailable` (voice cloning not enabled for your account, or the voice is paused), `voice_passport_lyrics_refused` (the lyrics failed the voice-safety check). In every case except the first the song is still made with `timbre`.

## The three gates [#the-three-gates]

When the song reaches a gate it answers `status: "waiting"` with `gate.kind` set, and nothing runs until you answer:

| Gate | What you see | Answer |
| --- | --- | --- |
| `plan` | Up to 3 plan variants in `gate.variants`: title, genre, BPM, meter, mode, sections and instrumentation, each with the producer's rationale | `{"gate": "plan", "variant": 0}` (0–2) |
| `demo` | The arranged demo in `demo_asset_id` and the team with each player's rationale | `{"gate": "demo", "approve": true}` |
| `final` | The final mix in `final_asset_id`, stems in `stems_asset_ids`, the critic's last review | `{"gate": "final", "approve": true}` |

```bash
curl https://ai.codai.ro/v1/studio/music-room/$ID/choose \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"gate": "plan", "variant": 1}'
```

At the demo or final gate you can also **direct one player**, like a producer in the studio. The player re-plays its part (one section or the whole song) and the demo is re-rendered:

```bash
curl https://ai.codai.ro/v1/studio/music-room/$ID/direct \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role": "drums", "section_id": "chorus1", "direction": "lay back on the chorus, fewer fills, more ghost notes"}'
```

`role` is one of `producer`, `composer`, `lyricist`, `arranger`, `drums`, `bass`, `guitar`, `keys`, `strings`, `brass`, `winds`, `balkan_lead`, `balkan_rhythm`, `percussion`, `synth`, `vocal_producer`, `sound_designer`, `mix_engineer`, `mastering_engineer`, `critic`, `rights`; `direction` is at most 500 characters. A gate left unanswered for 7 days fails the song (`error: "gate_expired"`) and releases any hold.

## Quota and budget [#quota-and-budget]

Songs are counted per calendar month (UTC): every Music Room song that reached `ready` or is still running.

| Plan | Songs included per month |
| --- | --- |
| Pro | 4 |
| Builder | 12 |
| Max | 30 |
| Team | 10 per seat |
| Free, Lite, Student, BYOK | 1 |

Within the quota a song is free for you (`quota.within: true`). Beyond it every step is quoted, held on your wallet and settled with the real cost — `402 insufficient_funds` when the wallet is short. `budget_micro_usd` caps one song either way; `spent_micro_usd` shows what it cost so far. Agent turns are token-metered under the public model `codai` (usage model `codai::music-<role>`, prompt caching on). Check what is left with `GET /v1/studio/music-room/quota`.

## Errors [#errors]

| Status | Code | When |
| --- | --- | --- |
| `400` | `invalid_request` | The body does not match the schema |
| `402` | `insufficient_funds` | Beyond the quota and the wallet cannot cover the next step |
| `404` | `not_found` | Unknown id, or another account's song |
| `409` | `not_at_gate` | `choose` or `direct` while the song is not waiting at that gate |
| `429` | `too_many_music_rooms` | Two songs are already running for you |
| `503` | `media_ops_unavailable` | The music renderer is not configured on this gateway |

## Credits [#credits]

`credits` lists the lines to publish with the song: CC-BY sample libraries used by the players and "Built with Llama" when a symbolic helper ran. Every output carries AI marking like the rest of codai Studio.

## SDKs [#sdks]

```ts
const room = await codai.studio.musicRoom.create(
  { brief: 'a cheerful wedding song about two old friends', language: 'ro', genre: 'hora' },
  { idempotencyKey: 'song-42' },
);
let r = await codai.studio.musicRoom.wait(room.id, { untilGate: true });
if (r.gate?.kind === 'plan') r = await codai.studio.musicRoom.choose(r.id, { gate: 'plan', variant: 0 });
await codai.studio.musicRoom.direct(r.id, { role: 'drums', direction: 'fewer fills' });
const { remaining } = await codai.studio.musicRoom.quota();
```

```python
room = client.studio.music_room.create("a cheerful wedding song about two old friends", language="ro", genre="hora")
r = client.studio.music_room.wait(room["id"], until_gate=True)
if r["gate"] and r["gate"]["kind"] == "plan":
    r = client.studio.music_room.choose(r["id"], "plan", variant=0)
print(client.studio.music_room.quota()["remaining"])
```

TypeScript: `studio.musicRoom.create / get / list / choose / direct / quota / wait` (`wait(id, { untilGate, intervalMs, timeoutMs, signal })`). Python: `studio.music_room.create / get / list / choose / direct / quota / wait` (`wait(id, until_gate=, interval=, timeout=)`).

## Agent tools [#agent-tools]

The codai desktop, phone and VS Code agents and the [MCP Studio toolset](./clients.mdx) use the same workflow through four tools: `music_room_create` (start a song; `auto` only when you asked to just make it), `music_room_status` (read and advance it), `music_room_choose` (answer a gate with your decision) and `music_room_direct` (talk to one player).
