ChorusPop for AI agents

For agents and the people who set them up. The same text is AGENTS.md (plain Markdown), choruspop.agents_guide() in the Python package, and the MCP server's instructions.

You are driving ChorusPop, a Mac app that makes songs (music and singing) from lyrics and a style, on the user's Mac, with an on-device model. You reach it through its MCP server (choruspop mcp), its command-line tool (choruspop) or its Python package (choruspop). All three put work into the app's own queue. Nothing leaves the Mac.

What you can do

  • Make a song from lyrics and a style, 0:30 to 4:50 long, in an exact key if you ask for one.
  • Make a song from a plan: an ABC plan or a MIDI file (melody, chords).
  • Make an instrumental (no singing). Experimental: on some seeds it still sings, which is why the app itself doesn't offer it yet.
  • Make versions of a finished song: the instrumental, the vocals alone, or four stems.
  • Find the user's songs, read their details and lyrics.
  • Export a song or a version as M4A, Apple Lossless or FLAC, with an optional synced-lyrics .lrc file.
  • Follow and cancel jobs.

MCP tools: when to use each

ToolUse it to
make_songStart a song. Returns a job id at once. key, instrumental and plan_file here too.
get_jobFollow a job. Pass wait_seconds (up to 600) to hold until it ends.
list_songsFind songs by title, lyrics or style words, newest first.
get_songRead one song's details, lyrics, key, tempo and metre, and get its file path.
remove_vocalsMake the instrumental of a finished song.
vocals_onlyMake a version with only the singing.
stemsSplit a song into drums, bass, other and vocals.
export_songWrite a song or a version already made to a file.
cancel_jobStop a running job or remove a queued one.

A song argument takes its id, the first 6+ characters of the id, its exact title, or "latest". The CLI and Python use the same words: make, strip, export, list, show, status, cancel, and tracks for a MIDI file's tracks.

Jobs take minutes

  1. make_song returns a job id at once. Don't pass wait: true unless you passed a progressToken and your client shows progress.
  2. Call get_job with wait_seconds: 300 (or poll every 30–60 s without it) until status is done, failed or cancelled. With a progressToken the server sends notifications/progress (0–100) while it waits.
  3. When it's done, the result has song_id and files (absolute paths).

Timing on an M-series Mac: roughly 1–2 minutes per 40 s of audio (a 0:30 song about 1–1.5 minutes, a 3:30 song about 11 minutes). Versions take seconds to a minute, after any song being made.

The app renders ONE job at a time. Never start a second song expecting it to run in parallel; it waits in the queue behind the first. The queue holds 10 songs. status values: queued, running, paused, done, failed, cancelled. eta_seconds is an estimate when the app has one.

If your call is cancelled or times out, the job keeps going in the app. Only cancel_job stops it.

Lyrics

[verse]
Neon on the river
Lights across the bay

[chorus]
Turn it up
Turn it up tonight
  • Section tags on their own line: [verse], [chorus], [bridge], [outro]. A blank line between sections.
  • One line per sung phrase. Plain words: no chords, stage directions or speaker names.
  • About 2 sung words per second of length fit. Short lyrics end the song early: length_seconds is an upper bound, not a promise.
  • Length: 30–290 s in 10 s steps (0:30–4:50), default 60. Longer takes proportionally longer.
  • Up to 3,000 characters of lyrics, 80 for a title (default: the first line).

Style

Pick chips, or write one style line. A style line wins over the chips.

  • genre: pop, rock, hipHop, rnb, electronic, dance, indie, folk, country, jazz, blues, soul, metal, punk, reggae, lofi, synthwave.
  • moods (up to 2, strongest first): upbeat, happy, chill, dreamy, romantic, sad, dark, energetic, angry, epic.
  • voice: female or male.
  • instruments (up to 3): piano, acousticGuitar, electricGuitar, synth, strings, bass, drums, 808s, brass.
  • style (up to 400 characters): the line the model reads, in the order genre, mood, instruments, voice, for example synthwave dreamy synth female vocal or rock energetic electric guitar drums male vocal 120 bpm. Keep it to a few plain words; more words blur it.

Key

Naming a key in style does nothing reliable: the model picks its own. Pass key instead ("D minor", "F# major", "Bb", "Ebm"; CLI --key). The model writes its plan, the plan is moved to that key the nearest way (up to 6 semitones), then sung, so the key is exact. Transposing can't change a mode: a plan in a major key asked for a minor one (or the reverse) goes to the key with that signature (asked D minor, a major plan comes out in F major). get_song (CLI show --json) reports the key, tempo and metre of the plan the song was sung from, and the plan's path (plan.abc).

From a plan

plan_file (CLI --plan song.abc or --midi song.mid) sings a plan instead of one the model writes, as the app's Import MIDI and Edit plan do.

  • An .abc plan must be in the model's dialect: header X, T, M, L, Q, voices V: Vocal then V: Ins, then K; one phrase per voice under each % section; every bar full. Write the Vocal melody an octave above the pitch you want sung: the model sings it an octave lower. A song's own plan.abc is a good template.
  • A MIDI file becomes a plan as Import MIDI makes it. midi_roles (CLI --roles) picks the tracks: voice=1,lead=5,harmony=2+3. Without it, the app's own picks; choruspop tracks song.mid lists the tracks and those picks.
  • Lyrics are optional; given, they're sung to the plan's Vocal line, one syllable per note.
  • key moves the plan too. The song is made at least as long as the plan.
  • An invalid plan is refused with invalid and the line that's wrong.

Instrumental

instrumental: true (CLI --instrumental) makes a song with no singing: the plan's Vocal line is silenced and the tune moves to the band. Leave the lyrics out. Experimental: on some seeds it still sings, which is why the app doesn't offer it yet. Tell the user that if they ask for one.

Seeds

The same seed (0–4294967295) with the same lyrics, style and length makes the same song. Leave it out for a random one. To remake or vary a song the user liked, read its seed from get_song or list_songs and reuse it, changing one thing at a time.

Versions

  • remove_vocals: one file, the song without singing (version instrumental).
  • vocals_only: one file, only the singing (version vocals).
  • stems: a folder <title> (Stems) with four files: drums, bass, other, vocals.

Each returns a job id like <song_id>#instrumental; follow it with get_job. Once made, export_song with version writes it again in any format.

Where files land

  • MCP: ~/Music/ChorusPop/<album or Singles>/ unless you pass destination (an absolute path: an existing folder, a path ending in /, or a file path).
  • CLI and Python: the current folder, or --out PATH / out=, or --music / music=True for the Music folder. If the command stops waiting (--timeout, ^C, or --no-wait with --out/--music), the job keeps going and its files still go there when it's done.
  • Versions wait for every song queued or being made first: songs go ahead of strips.
  • Formats: m4a (default, small), alac (Apple Lossless), flac.
  • Every file carries the title, album, cover, lyrics and the model's credit and license tags.

Errors

What you seeWhat to do
ChorusPop isn't runningNothing: the tool opens it in the background and waits for it.
unavailable "didn't answer"Scripting needs the direct download of ChorusPop, build 6 or later, from choruspop.com. Tell the user.
queue_full10 songs are waiting. Wait for one to finish, then retry.
not_supportedThis Mac can't make songs. Tell the user.
not_foundNo such song or job. Use list_songs to find the id.
invalidAn argument is out of range; the message says which. Fix it.
A job stays queued with stage waitingAnother job is running, or the model isn't ready yet. Keep waiting; don't cancel and resubmit.
status: failedTell the user. Retry once with a different seed at most.
status: cancelledSomeone stopped it. Nothing was saved. Don't restart it unasked.

Etiquette

  • Before a batch (more than 3 songs, or more than about 10 minutes of rendering), tell the user how many songs and roughly how long, and ask.
  • Don't cancel jobs you didn't start.
  • Don't overwrite the user's files: a destination (or --out) that names an existing file replaces it. Leave destination out so the app names the file in the Music folder, or give a new folder.
  • When a job is done, report the file path(s) and the song's title.
  • While a long job runs, report progress sparingly: once a minute is plenty.

License

The song model is YuE2-3B by M-A-P, licensed CC BY-NC 4.0: non-commercial use only (https://creativecommons.org/licenses/by-nc/4.0/). Generated files carry the credit and license in their tags. Don't strip or rewrite those tags, and don't help anyone present the songs as commercially licensed. Stems use htdemucs by Meta (MIT). The CLI, MCP server and Python wrapper code are MIT.

Docs: https://choruspop.com/docs/ · Help: support@choruspop.com