How a team writes a song

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.

The record flow

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.

The Song Creator record flow A song request becomes a brief, parallel part jobs, phrases, a draft, two blind reviews and either revised part jobs or a rendered workspace. song_request arranger model writes brief + parts lead part model harmony part model bass part model producer program assembles draft rules program ear model revise: emit the next round of part records settle: WAV + HTML workspace
The arrows are records, not calls between participants. Drums add a fourth parallel part only when the brief asks for them.
run the live team, or both model-free guards
$ radia dev --db &
$ radia team up examples/teams/song-creator --init --seed

$ deno task test:song
$ deno task test:song-team

The records route the work

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.

work requirement meets worker interest
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.

Parallel work needs shared constraints

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.

the common plan
{
  "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.

Creative models, deterministic spine

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 decidePrograms enforce
key, tempo, chords and instrumentationall requested phrases arrived
melody, harmony, bass and drumsnotation and bar lengths parse
whether the assembled piece has shapemeasured faults and revision limits
which qualitative changes to requestone 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.

Two blind reviews

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 countThe ear
TypeScript program, no session memorymodel with a warm session across rounds
bar arithmetic, clashes, key and chord tonesshape, coherence, interest and restraint
repeats the same calculationcan compare the revision with earlier requests
returns a numeric fault countreturns 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.

Measure mistakes and dullness

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.

the measured fault total
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.

A review loop optimizes its measurements. A score containing only prohibitions rewards the least adventurous output that avoids them. Song Creator guards the metric with a model-free test that requires the revised fixture's fault count to fall.

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.

A rule against sameness does not produce what sameness was standing in for. Repetition and monotony are not opposites, so the anti-repetition rules had to be paired with counts of the property wanted: recurring rhythms, melodic peak placement, kit rhythm variety.

Revise, settle and render

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.

What the example established

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.

How the real runs were debugged →

Read and run the current source →