An arranger plans the piece, several players write apart, two reviewers judge the assembled score, and a producer either asks for another round or renders a playable history. Models make the musical decisions. Records carry the state and route the work. Programs enforce the parts that must be repeatable.
One song_request becomes a brief and one part record per instrument.
The requested players work in parallel. Their phrases meet for the first time in a draft,
which is reviewed once by code and once by a model. Rejected work becomes another round;
settled work becomes audio and an HTML history in a workspace.
$ radia dev --db &
$ radia team up examples/teams/song-creator --init --seed
$ deno task test:song
$ deno task test:song-team
Song Creator owns eight kinds: song_request, brief,
part, phrase, draft, review,
verdict and note. Radia does not assign meanings to them. Their kind
declarations state the indexed routing fields and teach participants how each record is used.
A part record states the required instrument. A member's standing pattern states the instrument it accepts. Their match routes the work without putting a member name on the record.
part { instrument: "harmony", song, round }
+
agent:ben listens for { kind: "part", match: { instrument: "harmony" } }
=
Ben may claim the part under a fenced lease
The arranger controls participation by deciding which part records exist. If a piece needs no drums, it emits no drum part. Pip remains a member, but no harness is launched and no model call is paid for.
team.json is the coordination manifest: kinds, member patterns, grants, services,
seed and completion condition. It is not the whole application. The prompts and programs
implement the transitions that produce the next records.
The lead, harmony and bass players compose simultaneously and cannot read one another's phrases. A description such as “bright and in D” did not keep independently written lines in the same harmonic plan. The brief now carries one chord per bar, along with key, tempo, meter and length. Every player reads the same structure before writing.
{
"key": "D major",
"bpm": 104,
"meter": { "beats": 3, "unit": 4 },
"bars": 8,
"chords": ["D", "G", "D", "Bm A7", "Bm", "G", "A7", "D"],
"parts": ["lead", "harmony", "bass"]
}
Agents working apart need shared, checkable constraints for the facts their outputs must agree on. Prose still carries disposition and musical intent; fields carry meter and harmony.
Players write a compact notation such as C4/4 E4/8 G4/8. The parser checks every
bar against the meter and names the offending bar. That turns “the output sounds broken” into
a repair request a player can act on.
What the notation cannot express, no prompt can ask for. Runs kept returning parts whose every note landed on a beat, because there was no tie to write an anticipation with, and progressions that only turned over on a downbeat, because a chord entry held one chord per bar. Both are now expressible.
Models arrange, compose and make the qualitative judgment. Plain TypeScript performs fan-in, notation validation, metric calculation, round accounting, rendering, artifact storage and completion.
| Models decide | Programs enforce |
|---|---|
| key, tempo, chords and instrumentation | all requested phrases arrived |
| melody, harmony, bass and drums | notation and bar lengths parse |
| whether the assembled piece has shape | measured faults and revision limits |
| which qualitative changes to request | one draft, review pair and settlement per key |
The producer is an application coordinator, not a model and not a Radia workflow graph. It knows that phrases form a draft, verdicts cause revision or settlement, and a settled score is rendered. Radia supplies the records, matching, grants and leases through which those transitions happen.
Every phrase handler checks whether the round is complete. A content-derived idempotency key,
draft:<song>:<round>, makes competing completions one logical write. The same
technique protects review dispatch and final settlement against duplicate execution.
The producer emits two claimable review records for the same draft. The checker claims
{by: "rules"}; the critic claims {by: "ear"}. Their grants do not
let either read the other's verdict before answering.
A draft that does not parse gets only the first of them. Nobody can hear a score the renderer refuses, and a model asked to judge one answered anyway: four rounds of a live run carry an ear approving a peak on a piece that would not render, each a paid turn and a false line in the history.
| The count | The ear |
|---|---|
| TypeScript program, no session memory | model with a warm session across rounds |
| bar arithmetic, clashes, key and chord tones | shape, coherence, interest and restraint |
| repeats the same calculation | can compare the revision with earlier requests |
| returns a numeric fault count | returns qualitative approval and specific asks |
“Ear” is a role name, not an audio capability. The critic reads the assembled notation; no model on the team hears the WAV. Rendering every round lets a person make that comparison afterwards.
Blind review makes disagreement evidence. The records can show whether both reviewers found the same problem, only the calculation found it, or only the qualitative reading did.
The first scoring pass counted only violations. The loop improved that number by producing cautious music: repeated quarter notes, narrow ranges and lines that avoided expressive movement. The analysis now counts selected forms of dullness alongside harmonic and notation faults.
faults =
dissonance
+ parallels * 2
+ outOfKey
+ offChord
+ bland * 2
+ unansweredLeaps
+ emptyBars * 3
+ unresolvedEnding * 2
The checks also distinguish a landed chromatic note from a passing one and an unanswered leap from one that returns. The loop must leave room for the gestures it is meant to improve.
Intent can qualify a measurement. groove: true exempts the rhythm section from the
one-note-length rule and the bass from the parallel-motion rule, because a steady pulse locked
to the harmony may be the requested style. It does not disable the rest of the analysis.
Correcting that overshot. Every dullness rule pushed away from repetition, so a lead returned eight bars in eight different rhythms, as hard to remember as eight identical ones. The metric now also counts rhythms that never recur, where the melody puts its highest note, and how many different rhythms a kit plays.
When review asks for changes, the producer emits the next round's part records. Each player receives the combined requests for its own instrument. A player with no requested change is told to return its previous part unchanged, keeping the complete round explicit.
Warm harness sessions let players revise their earlier work instead of composing a new piece on every round. A fresh song clears those sessions, and resumed prompts inspect the record's round before assuming they are continuing old work.
Settlement has three outcomes. Both reviewers can approve; the ear can approve while the
deterministic count remains within the measured tolerance; or the round ceiling can stop the
loop. The last case is termination, not approval. It renders the newest readable draft, or
writes an ok: false final note if no round produced one.
Parseable rounds consume the musical revision budget. A separate hard ceiling bounds repeated notation failures, so malformed bars neither spend every opportunity for musical revision nor run forever.
The synthesizer is deterministic: the same score produces the same PCM, WAV bytes and artifact
digest. The producer renders the rejected rounds as well as the selected one and writes
song.wav, the round audio and an HTML history into a workspace. A short-lived
capability URL makes that tree playable without putting the producer's credential in a
browser.
The example shows a content-routed application with an implicit topology and explicit behavior. Kind and body fields say what work is needed. Interests and grants determine who can claim it. The participants decide which records come next, and deterministic services protect concurrency and termination boundaries.
It also produces evidence about quality. The model-free run requires the measured fault count to improve, while the rendered history lets a person hear what the number omitted. A metric that stops distinguishing revisions fails a test instead of surviving as a claim in documentation.
Running the full team exposed stale work, lazy lease expiry, dead services that still looked interested, warm sessions crossing songs and a verdict arriving after its round was superseded. Those failures led to a separate method for reading the space and reproducing faults without paying for another model round.