Common Timecommontime/1 · 1.2a

A protocol for making independent clients agree on musical time.

No audio crosses the wire. One anchor does, and after that only integer ticks and commands placed on them. Every client already holds the material; the protocol decides when.

Session readout

Session tick
Bar
Beat
Meter
4/4
BPM
118
PPQ
960
tick = (1789257600000) × 118 × 960 / 60000 =

This page derives its own tick from a fixed anchor — 13 September 2026, 00:00 UTC — using integer arithmetic and floored division, exactly as a client must (N14). It is what a client does, minus the audio. The ceiling is 9 007 199 254 740 991: a tick must fit in 53 bits, because JSON numbers are floating point (N12). At 118 BPM that is roughly 151 000 years.

§1

What crosses the wire

Carried

  • anchorEpochMs · bpm · beatsPerBar · ppq
  • integer ticks
  • start · stop · gain · param · material
  • sha256:<hex>
  • telemetry

Never carried

  • audio
  • note data
  • prompts · model identifiers
  • rights metadata · user identity
  • world state · directives · suggestions
Why material is audio, not a sequence

Two implementations with different instruments would render the same note sequence as different audio. Material is therefore pre-rendered audio, addressed by content digest, and the protocol carries only identity and time. How the material was produced, stretched, resampled or generated is not the protocol’s business.

§2

One anchor, integer ticks, immutable tempo

A session defines its time with three numbers and one instant. Tempo must not change during a session. Every time value in the protocol is a tick; bars are a presentation form and belong in the user interface, not on the wire.

One anchor, integer ticks, immutable tempo
FieldMeaning
anchorEpochMsPhysical instant of tick 0. Immutable.
bpmQuarter notes per minute. Immutable.
beatsPerBarDefault 4. Immutable.
ppqTicks per quarter note. The value is 960.
ticksPerBarDerived: ppq × beatsPerBar — 3840 in 4/4.

This is what a fractional bar position does not give: loop length is always an integer. Sixteen bars is 61 440 ticks whether the tempo is 118 or 120, so comparison, hashing and equality are exact in every implementation.

N14 · the first thing an implementer gets wrong

A tick must be derived using floored division — toward negative infinity — not truncation toward zero and not rounding. The remainder used for a material position must be non-negative. Both differ from the native operators of several languages:

// JavaScript BigInt: both wrong for this purpose
(-7n) / 2n   // -3n   — truncates toward zero, want -4n
(-7n) % 2n   // -1n   — negative remainder, want 1n

// Correct
let t = q / 60000n;
if (q < 0n && q % 60000n !== 0n) t -= 1n;

A tick may be negative, because a session may be announced before its anchor. That is not an edge case; it is how a set is scheduled.

§4

Ten messages, five operations, no optional fields

JSON over WebSocket, one message per frame, a type field on every message. There is no extension point other than param, and there are no optional features to negotiate — a conformance profile is something an implementation can hide behind.

Ten messages, five operations, no optional fields
MessageDirectionFields
ct.hellobothv
ct.pingclient →t0
ct.pong→ clientt0, t1
ct.session→ clientid, anchorEpochMs, bpm, beatsPerBar, ppq
ct.load→ clientid, material, lengthTicks
ct.readyclient →ref, readyAtTick
ct.refuseclient →ref, reason
ct.cmd→ clientid, atTick, slot, op, value, rampTicks
ct.snapshot→ clientatTick, cmds[]
ct.stateclient →offsetMs, minRttMs, jitterMs, minLeadTicks, late[], degraded

Two rules that make the control plane replayable

N3 · a command is never answered

A command whose atTick has already passed is still applied, and its effect is computed as if it had been applied at atTick. Lateness is reported in telemetry, not negotiated. A command is never discarded for lateness alone.

N8 · state monotonicity

For a given slot and parameter, the command with the highest atTick wins. Application is therefore idempotent and order-independent: two clients receiving the same commands in different orders arrive at the same state. A snapshot is not a special structure — it is the set of winning commands, each with its original atTick.

§6

Obligations are outcomes, not mechanisms

The specification says what must be true of the audio, not how to achieve it. Sample insertion, playback-rate trim, rescheduling — choose freely. Two implementations that pass with different mechanisms is a good result, because it proves the obligation is mechanism-independent.

Obligations are outcomes, not mechanisms
IDOutcome required
V1The sample leaving the output corresponds to the current session tick within tolerance. The mechanism is deliberately unspecified.
V2Each loop iteration derives its start from session time — never from the end of the previous one. Concatenation accumulates error and is forbidden.
V3Material a client does not have is silence for that slot. Not a delay, not a substitute, and never a stalled session for everyone else.
V4A client that cannot meet its bound stops emitting audio and reports degraded. Failing loudly is an obligation, because a client that drifts quietly is worse than one that stops.
The limit of accuracy, stated on purpose

The protocol must not guarantee absolute alignment to the server clock. Path asymmetry introduces a bias that cannot be detected from inside the protocol at all, and it is bounded by ±minRTT/2. Offset sampling must therefore select the sample with the lowest round-trip time — not the median, which does not remove queueing asymmetry — and an implementation must report minRttMs and must not present the offset as exact.

Status

Where this actually stands

Specification
1.2a
Implementations
2
Optional features
0
Open items
12
Cross-run
blocked

A protocol page that claims to be finished is not telling you anything you can check. This one is deliberately specific about what is measured and what is not.

Decided

Version 1.2a is approved. All twenty-three review items raised during drafting were addressed. The specification has exactly one deliberate gap: the tolerance value that V1 and V4 refer to. It is absent because the measurement that determines it has not been performed, and it will be closed by measurement rather than by discussion.

Measured

The tick arithmetic passes 34 tests with no dependencies, in integers throughout. The measurement rig reads a known 10.0000 ms delay correctly — but only after PHAT weighting was added: unweighted cross-correlation read the same tape as 0.9086 ms, exactly two periods off, with a correlation coefficient of 0.9969 and no warning of any kind. A correct engine holds p95 0.394 ms against a simulated crystal; a concatenating one breaks at p95 12.47 ms and drifts 4.37 ms per hour. A system clock step of 250 ms mid-run threw a drift estimate to −2965 ppm for two minutes when the true figure was +125.

Not measured

Every number that needs an analogue output and a recorder. The accuracy claims above are made against a simulated crystal, which is a calibration and not a measurement, and they are not the tolerance value. Nothing has yet run on two machines across a real network for three hours, which is the length of a set and not a safety margin.

The cross-run is blocked, and that is the gate working

Two independent implementations exist. The second was written from the specification text alone, by an author who has never seen the first implementation’s code. Their cross-run does not get past the first message: N16 requires closing the connection when the v values differ, but the specification never stated what the value is. One sent commontime/1, the other commontime/1.2, and the connection closed correctly in both directions.

Neither author changed their value to match the other. That refusal is the point of the exercise: a value agreed between two implementers is a private convention that no third party could reproduce. It belongs in the specification before it belongs in anybody’s source file.

Ask

Write the third implementation

The two implementations produced 13 and 9 open items. Four of them are the same item. That is 18 distinct findings and an overlap of 22 %.

Overlap that low is measurable information about what is left. Capture–recapture puts the findable population at 27–29 items, so roughly ten holes are still unfound — and that is a floor, not an estimate of the worst case: shared blind spots fall outside the population entirely, and gaps obvious enough for everyone to find inflate the overlap. Both biases point the same way.

An implementer finds the gaps that their own structure runs into. One implementation sends loads to a joining client, so its author hit the joining message order; the other does not send them, so its author never did. This is why the useful variable is the number of implementations, not the number of review passes — and why the most valuable thing anyone can do with this specification is implement it a third time.

The more different the structure, the more it finds. Preferably one without arbitrary-precision integers, because that hits N12 and N14 from a direction neither existing implementation can.

Three rules, and the third is the one that matters

Do not fix the specification. If a passage is unclear, contradictory or missing, you do not resolve it — you record it and work around it, or you stop. A silent resolution is exactly how two implementations drift apart while both look correct.

Do not extend the protocol. Ten messages, five operations, one extension point. If something feels missing, it probably belongs to the application layer.

Write down every guess, at the moment you make it. A finding with two plausible readings that lead to different implementations is worth more than working code. A guess that turned out right but was never recorded is indistinguishable from luck.

Cite the versioned clause, not the clause: “§2 / commontime/1”, never “§2”. The specification is under the same version control as the tests that check it.

Documents

The specification and everything around it

The normative text is one document. The others exist so that the normative text does not have to argue for itself, apologise for itself, or keep a diary.

Application layer — not the protocol

Common Time exists because something needed it. These documents describe that something, and they are not part of the specification — a conforming implementation owes them nothing.