Skip to documentation
API reference

loops.document/v1

API reference

The v1 wire format is immutable. Parsers reject unknown, malformed, non-canonical, or oversized input instead of guessing.

Document schema

A loop is a required title plus canonical, MIDI-expressible content: integer bpm, integer bars, and ordered typed tracks. It is not a record containing a second stored midi byte field.

{
  protocol: "loops.document/v1";
  title: string;
  bpm: integer;
  bars: 4..16;
  tracks: Array<NotesTrack | DrumsTrack>;
}

A notes track has an opaque document-wide trk_ ID, name, zero-based GM1 gmProgram, lineage, and melodic events. A drums track omits the program and uses GM percussion pitches 35–81. Every event has a unique evt_ ID, MIDI pitch, half-open step interval, and velocity 1–127. Drum hits occupy exactly one step.

Time is fixed 4/4: 4 beats and 16 sixteenth-note steps per bar. Empty documents and empty tracks are valid.

Self-contained URL

#l1.<codec>.<payload>.<sha256>

Codec c is canonical CBOR. Codec d is the same CBOR followed by raw DEFLATE. Payload and digest use unpadded base64url. The digest is SHA-256 of the uncompressed canonical bytes, so compression does not change content identity.

The complete fragment is the canonical artifact. A browser does not send it in the HTTP request. Keep it intact and do not upload it to a mutation service.

Compact agent text

Version L1 is a lossless, line-oriented view. Records are tab-separated and already sorted in canonical order.

L1
D <json-title> <bpm> <bars>
T <track-id> <n|d> <json-name> <gm-program|-> <o|d> [operation-id source-count]
S <source-track-id> <source-digest>     # repeated source-count times
E <event-id> <pitch> <start> <end> <velocity>
X
Z

Records are tab-separated. T..X repeats once per track. n=notes, d=drums,
o=original lineage, d=derived lineage. JSON strings use canonical JSON
escaping. Records, tracks, sources, and events must already be in canonical
order.

T uses n for notes and d for drums. Lineage is o for original or d followed by an operation ID and checked source records.

Bundled CLI

Install the edit-loops skill archive, inspect its one edit-loops/ directory, and run:

bun <skill-path>/scripts/loops.mjs inspect '<loops-url>'
bun <skill-path>/scripts/loops.mjs verify '<loops-url>'
bun <skill-path>/scripts/loops.mjs encode document.loops
bun <skill-path>/scripts/loops.mjs add-track '<loops-url>' track.loops --operation op_name --from trk_source
bun <skill-path>/scripts/loops.mjs replace-track '<loops-url>' trk_target track.loops --operation op_name --from trk_target
bun <skill-path>/scripts/loops.mjs import-midi input.mid
bun <skill-path>/scripts/loops.mjs export-midi '<loops-url>' output.mid

Inside Jungle, the equivalent command prefix is bun run protocol from projects/loops. Standard output stays machine-composable; warnings and failures use standard error.

Operations and lineage

loops.operation/v1 envelopes contain an opaque op_ ID, the exact base document digest, and one pure discriminated operation: create-document, add-track, replace-track, remove-track, move-event, add-event, remove-event, or resize-document. Applying one returns applied, unchanged, conflict, or rejected. Conflict and rejection preserve the base.

The bundled CLI currently constructs add-track and replace-track operations. Repeat --from <track-id> for each current source. The CLI resolves and hashes those tracks from the exact base rather than accepting agent-invented digests. Stable operation IDs make exact replay deterministic.

There is no unauthenticated hosted mutation endpoint. The CLI applies operations locally and emits a new self-contained URL. Optional authenticated account sync stores checkpoints; it is not the public protocol API.

Standard MIDI interchange

Export writes canonical Type 1 MIDI at 96 PPQ (24 ticks per Loops step), one conductor track, one track per layer, independent melodic channels, and channel 10 drums. Loops metadata preserves IDs and lineage for an exact Loops export/import round trip.

Import accepts Type 0 or Type 1 only when the file maps exactly to the Loops grid and model. Tempo or meter changes, off-grid notes, unsupported controllers, pitch bend, aftertouch, SysEx, SMPTE timing, and lossy projections are rejected. Raw SMF is interchange, not a duplicated canonical storage field.

Hard limits

ValueLimit
Bars416
Tracks16
Melodic tracks15
GM1 programs128 (0–127)
Events per track512
Events per document2,048
Title80 UTF-8 bytes
Track name48 UTF-8 bytes
Canonical CBOR24,538 bytes
Raw fragment32,768 characters
Agent text524,288 UTF-8 bytes
Standard MIDI input524,288 bytes