Work with Coding Agents
A coding agent (Claude Code, Codex, or your own) works from a shell. Every step here is a
resonon command or a line of the piece, so the agent can check its work without a person, and the
person listens at checkpoints.
Give the agent the reference
Section titled “Give the agent the reference”resonon reference prints the language reference for the version the project uses: the syntax,
idioms, the mini-notation and every standard-library function with its signature. The same
document is at /docs/llms.txt for the current version. Tell the agent to read it
before it writes code.
resonon new and resonon init write an AGENTS.md into the project. It tells an agent about the
reference and this page. Codex and most other agents read AGENTS.md. Claude Code reads
CLAUDE.md, so give it a CLAUDE.md that imports the file:
@AGENTS.mdWrite what is special about your piece (its key, its tempo, the sound you want) in AGENTS.md
too.
The loop
Section titled “The loop”| Step | Command | It tells you |
|---|---|---|
| 1. Check | resonon check --message-format json | Syntax, undefined names, arity and types, without running anything |
| 2. List | print(to_json(notes(source, cycles))); | The notes and drum hits a part plays, as text |
| 3. Render | resonon run --no-midi | WAV files of the stems and the mix, in renders/ |
| 4. Analyze | resonon analyze renders/<name> --message-format json | Levels, loudness, clipping, stereo and frequency balance |
| 5. Listen | a person | Everything the numbers cannot say |
Steps 1 to 4 open no audio or MIDI device, and each exits with 1 when it finds an error. Repeat them after each change. Stop for step 5 when a part is done, before the agent builds on it.
Write a piece the loop can run
Section titled “Write a piece the loop can run”resonon run runs the project’s src/main.non from top to bottom. Put the notes() lines and
the render() call at the end of it:
use "std/instruments" { Sampler, Kit };
set_project_title("Agent Loop");
let beat = [bd _ sd _];let drums = AudioTrack("drums").set_volume(-6);drums.set_instrument(Sampler(Kit("CR-78")));drums << beat;
let hats = AudioTrack("hats").set_volume(-12);hats.set_instrument(Sampler(Kit("CR-78")));hats << [hh*8];
// List: the drum hits of one cycleprint(to_json(notes(beat, 1)));
// Render: each track, and the mix, for 8 cyclesrender(#[drums, hats, master], 8);In the editor, these last lines run only when you select them, so the piece stays playable live.
- List the parts you want to check.
notes()takes a pattern, a timeline, a MIDI track or an array of MIDI tracks. Its output is in List the Notes a Pattern Plays. For a song made of sections, list the patterns the sections play. - Render every track and
master. A stem shows which track causes a problem in the mix. - Render enough cycles. Include the longest section. A track that plays a pattern loops until the render stops, so its reverb or delay tail is always cut. To keep a tail, make the piece a song that ends, and render a few cycles past its end: Render a Song.
- Give the piece a title.
set_project_title()names the render folder, so you can find the newest one.
resonon run --message-format json prints the output and any error as one JSON object per line
(Machine-readable output).
Read the analysis
Section titled “Read the analysis”resonon analyze measures the folder that the render wrote, master first. Each measurement is
defined in the CLI reference. In JSON, each key
has its unit in its name (true_peak_dbtp), and a level of no signal is null. A stem is the
track’s output; master.wav is the mix after the master’s volume.
Check these first:
| Measurement | Look for |
|---|---|
clipped_samples | 0 on every file |
true_peak_dbtp | Below 0 on every stem. On the master, about -6 to -3 while you mix; -1 or lower on a finished master |
integrated_lufs | Not null: a stem with no level plays nothing. Then compare the stems with each other |
bands | The energy where the part should have it: a bass in sub and low, hats in high |
correlation | Above 0 on the master. Below 0, parts cancel when they play in mono |
dc_offset_percent | Close to 0 |
trailing_silence_s | More than 0 when the piece ends with a reverb or delay, or the render cut the tail |
Loudness targets for a finished master, as integrated loudness:
| Destination | Integrated | True peak |
|---|---|---|
| Spotify, YouTube | -14 LUFS | -1 dBTP |
| Apple Music | -16 LUFS | -1 dBTP |
| Broadcast, EBU R128 | -23 LUFS | -1 dBTP |
| Broadcast, ATSC A/85 (US) | -24 LUFS | -2 dBTP |
Streaming services turn a louder master down to their level, so a louder master is not louder for
the listener; it only has less dynamics. Integrated loudness is measured over the whole file, so
measure the whole song, not one loop. A loop that repeats has a loudness range (loudness_range_lu)
near 0.
To let the agent see a part, add --spectrogram all. It writes a PNG beside each WAV, with the
cycles numbered along the top.
Listen at checkpoints
Section titled “Listen at checkpoints”The numbers show whether a mix is clean, not whether it is good. They cannot tell a groove that drags from one that swings, or a good sound from a bad one with the same level. Ask the agent to stop when a part is done, and listen to the render before it continues.
Related
Section titled “Related”- Errors & Warnings — what
resonon checkreports - Render a Project — what
render()writes, and where - Levels & Files — volume ranges, the pan law and what a render contains
- Command Line — every command and its options