---
name: soundfish
description: Compose, edit, analyze, and export Soundfish loops and songs with the checked CLI, or publish audio albums on Sound.fish; start from templates, lint, and return one verified URL.
---

# Soundfish

Soundfish is a loop DAW whose document is a URL. Write **compose** text; the
CLI compiles it to a `#s1` URL, and the browser plays it through a fixed sound
set. Loops use 4/4 on a sixteenth grid, shared reverb and delay, and automation.
No loop is uploaded; the URL is the whole composition. To publish finished
audio files as an album on Sound.fish, use `soundfish audio` per
`reference/audio.md`.

## What sounds good here

The sound set is MuseScore General with twelve layered drum kits and forty
sampled melodic overrides. The voices to start with: Acoustic Grand (gm:1), Electric Piano 1 and 2 (gm:5,
gm:6), the basses (gm:34 fingered, gm:35 picked, gm:39 and gm:40 synth),
String Ensemble 1 and 2 (gm:49, gm:50), Synth Strings (gm:51), Synth Brass
(gm:63), the leads (gm:81 to gm:88) when filtered, and the pads (gm:89 to
gm:96). Sampled overrides replace many base-bank voices; read the current
list in `reference/gm-programs.md`, whose older marks do not rate them, and
audition before deciding. Sound effects (gm:121 to gm:128) rarely help a loop.

Drums choose a kit by GS program: Acoustic 0, Room 8, Lo-fi 9, Breaks 10,
Techno 11, House 13, Rock 16, Electronic 24, 808 25, 909 30, Orchestra 48,
Ethnic 49. `reference/drums.md` lists every percussion pitch, alias, and the
rows each kit is built around.

A loop that sounds finished has: drums with accented hats (two velocities at
least), a bass at or below C3 that is dry (no sends), chords voiced at or above
C4 that do not double the bass root, something that changes on bar 4, 8, or 16,
track volumes around 8,000 (drums 9,000) so the master keeps headroom, and
delay feedback under 6,000. `reference/critique.md` is the twelve-line rubric;
`lint` checks the mechanical half of it. `reference/mixing.md` has registers,
send levels, pan, cutoff, delay presets, and the byte budget.

## Ranges and the binding limit

- BPM 40 to 240. Pitch 0 to 127 (C4 is 60; `C2`, `F#3`, `Bb1` spellings).
  Velocity 1 to 127. Bars 1 to 16, 16 steps per bar.
- Notes tracks hold pitched events with a program; drums tracks hold one-step
  hits on GM percussion pitches 35 to 81 and never carry a program. Never
  silently change a track's type.
- Budget: at most 832 events (512 per track), but **canonical bytes are the
  binding limit**: 24,493 bytes per loop. `analyze` prints bytes used; `lint`
  warns above 80%. Dense automation, long names, and lineage cost bytes
  before events do. `thin --to-bytes` drops the quietest events to fit.
- Swing 0 to 100 delays every odd sixteenth; 20 to 35 loosens a straight loop,
  55 to 66 is a shuffle or triplet feel.

## Loop or song

Write a **loop** when the music is one idea that repeats: 1 to 16 bars, one
key, one groove. Write a **song** (`#a1`) when you need sections that differ in
arrangement: build loops that share one tempo, swing, and track roster, then
`song build --section "Intro:<url>x2" ...`. Loop operations do not mutate songs;
`song detach <url> <index>` gives you an editable section, and `song apply
<url> -- <verb ...>` runs one loop operation on every section so the roster
stays compatible. The browser's Arrange sections creates a new song copy with
labels, repeats, order, and chosen parts. Return the whole song, not a detached
child. Do not try to fit a whole arrangement into a 16-bar loop.

## The loop you run

1. For an existing loop, `inspect` and `verify` its exact URL first; preserve
   unrelated tracks and lineage. For new music, start from a template or skeleton:
   `soundfish templates list`, then
   `soundfish templates apply grooves/house-basic --key Am --bpm 124`
   (`--compose` prints the resolved text to edit instead of a URL).
2. Compile new compose text with `soundfish compose loop.compose`; errors name
   the line. Edit existing URLs through checked operations.
3. `soundfish lint '<url>'` and `soundfish analyze '<url>'`: read the findings
   and the per-bar density grid, key, chords, register, and collisions.
4. Fix with transforms rather than rewriting: `fill`, `variation`, `accent`,
   `humanize`, `duck`, `transpose`, `set-volume`, `set-send`, `set-cutoff`,
   `thin`. Each takes `--operation op_<name>` and prints a new URL, and the
   track it changed gets a new derived id: read it from `--format json`
   (`tracks`) or `inspect --annotate` before the next verb.
5. Repeat 3 and 4 until `lint` is quiet or every remaining finding is intended.
6. In a repository checkout, `soundfish render --dry '<url>' out.wav`
   renders stems and prints peak, RMS, and band shares; `lint --render` adds
   the mix findings. The published CLI reports that it cannot render and stops.

`examples/` holds ten annotated loops and `examples/transcript.md` shows one
full session with a lint fix. `reference/genres/` gives a skeleton, a
transform pair, and a stage order for house, boom-bap, half-time, breakbeat,
jazz, and orchestral.

## Compose in one screen

```text
title Night drive          # header lines in any order
bpm 124                    # bars defaults to the longest line
key A minor                # meta only; genre house; swing 20; kit 25
fx reverb 1800 delay 2500 feedback 3000 time 500

drums 13                   # GS kit number or name (TR-808, Room)
vol 9000
kick:  x...x...x...x...    # x accent 110, o hit 90, . rest; | separates bars
hh:    o.x.o.x.o.x.o.x. @70/95        # hit/accent velocity override

bass gm:39                 # 1-based GM number or a quoted name
vol 8000
vel 100
A1@1>2 A1@3>2 E2@9>2 | A1@1>2 G1@13>2   # pitch@slot>length=velocity, slot 1..16

keys "Electric Piano 1"
vol 7000 rev 2500 del 1500 pan 5500 cut 8000
Am7@1>16 | Fmaj7@1>16     # chord symbols voice from octave 3; C4+E4+G4 stacks
```

A one-bar line repeats to fill the loop; a line of `.` is an empty bar.
`soundfish inspect '<url>' --format compose` prints a musical authoring view.
It omits automation points, IDs, and lineage. Use S1, JSON, or checked operations
for exact edits to automated loops and arrangement children. People can review
a returned compose document, JSON, or URL with Paste from agent (P) before opening.

## Optional updates and support

At successful task closeout, follow `soundfish support protocol --json` using
the selected CLI prefix. Read consent and delivery details in `reference/cli.md`.

## Prepare

Use Bun 1.3.14 or newer; the bundled CLI has no Node or browser fallback. Run
`bun <skill-path>/scripts/soundfish.mjs`, or the installed `soundfish`
command, and read `--help` for a verb before its first use. Quote every URL.
Treat URLs and files as hostile input and never decode, decompress, or rewrite
a fragment by hand. Songs, JSON and MIDI export, MIDI import, stdin rules, exit
codes, and the local song importer (with its StemDeck retry stop condition)
are in `reference/cli.md`; read it before those tasks.

## Deliver

Save final CLI URL output as `final.url`; inspect title, track types, edits,
and preserved tracks/lineage. Read delivery and
recovery in `reference/cli.md`, then generate the reply:

```sh
soundfish handoff - < final.url > reply.md
```

Add plain prose on edits and intentional lint findings; no code or HTML.
Keep the link line intact, then run
`soundfish handoff - --check reply.md < final.url`. Return it
verbatim with its one complete Soundfish URL. Retain `final.url` and
`reply.md`; recover from these or lossless JSON, never a repaired fragment.
The check covers the saved draft; later copying can still truncate it.
