Skip to content

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.

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:

CLAUDE.md
@AGENTS.md

Write what is special about your piece (its key, its tempo, the sound you want) in AGENTS.md too.

StepCommandIt tells you
1. Checkresonon check --message-format jsonSyntax, undefined names, arity and types, without running anything
2. Listprint(to_json(notes(source, cycles)));The notes and drum hits a part plays, as text
3. Renderresonon run --no-midiWAV files of the stems and the mix, in renders/
4. Analyzeresonon analyze renders/<name> --message-format jsonLevels, loudness, clipping, stereo and frequency balance
5. Listena personEverything 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.

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 cycle
print(to_json(notes(beat, 1)));
// Render: each track, and the mix, for 8 cycles
render(#[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).

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:

MeasurementLook for
clipped_samples0 on every file
true_peak_dbtpBelow 0 on every stem. On the master, about -6 to -3 while you mix; -1 or lower on a finished master
integrated_lufsNot null: a stem with no level plays nothing. Then compare the stems with each other
bandsThe energy where the part should have it: a bass in sub and low, hats in high
correlationAbove 0 on the master. Below 0, parts cancel when they play in mono
dc_offset_percentClose to 0
trailing_silence_sMore 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:

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

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.