Deckard

Stream protocol

Envelope, scheduling, control ops.

1. JSON envelope (REST or queued ops)

{
  "v": 1,
  "sessionId": "uuid",
  "actorId": "string",
  "authorId": "string",
  "layer": "canonical | ui_overlay",
  "master": false,
  "op": "DECK_LINE | DECK_BLOCK | DIRECT | CONTROL",
  "target": { "channelId": "c0", "domain": "mix | steps | gen | notes | auto" },
  "payload": "single deck line or object",
  "clientSeq": 42
}

Hub responds with { "ok": true, "seq": 17 } or { "ok": false, "code": "SKILL_DENIED", "message": "..." }.

2. Scheduling (perf step / lookahead)

The host advances perfStep in 16th-note steps (one sequencer column per step; 16 steps per 4/4 bar). Agents should target future steps, not “now”.

FieldOn deck.blockMeaning
effectivePerfStepoptionalApply merge when host perfStep >= this. If omitted (and no @ perf_step in deck), block is ASAP.
submitDeadlinePerfStepoptionalIf host perfStep exceeds this when the message is received, drop (late delivery). Omit = no deadline check.
asapoptionalIf true, ignore schedule and apply immediately when received.

Implemented in src/codj/Schedule.tish (coDjHandleIncomingTplBlockcoDjFlushScheduledForStep): late deliveries are dropped, asap/due blocks apply immediately, future blocks queue and flush when the playhead reaches effectivePerfStep. Queued blocks carry the sender's skillIds so skill-gating is re-checked at apply time.

Sequence lookahead: one sequence = 64 sixteenth steps (four 4/4 bars). Remote lanes may schedule blocks up to 4 sequences ahead: effectivePerfStep = hostPerfStep + 256. Use submitDeadlinePerfStep at least hostPerfStep + 384 (or omit) so delivery is not dropped while the playhead catches up.

direct from browser may include perfStep (host’s current step when the human sent the message) so the agent can compute effectivePerfStep and deadline relative to that instant.

3. WebSocket message types

See WS_AND_AGENTS.md. Summary:

typePurpose
join / joinedHandshake
deck.lineOne completed deck line
deck.blockMultiple lines atomically (+ optional schedule fields above)
deck.stream_chunkLive typing (agents)
directNatural-language direction to a target actor
state.snapshotResync
errorRejection

Every fanned-out message also carries skillIds — the gateway stamps the sender's declared skillIds (from join) onto each forwarded message (services/gateway/main.tish) so receivers can enforce skill-gating on apply. See CO_DJ_SPACE.md and src/codj/Skills.tish.

4. Control ops (master)

Payload for type: control, op:

oppayloadstatus
clear_overlay{ channelId? } empty = allImplemented (browser-side, src/ui/CoDjPanel.tish)
take_track{ channelId }Planned
release_track{ channelId }Planned
set_master{ authorId } — host-onlyPlanned
master_overwrite{ channelId, tplFragment }Planned

Only clear_overlay is handled today (it drops all overlays in scope on the receiving browser); the other ops are not yet wired.

5. Error codes

Codes the gateway actually emits (services/gateway/main.tish):

codeMeaning
BAD_JSONMessage was not valid JSON
JOIN_BADjoin missing a valid actorId
JOIN_FIRSTA non-join message arrived before joining

These are Planned (not yet emitted):

codeMeaning
SKILL_DENIEDLane lacks skill for op
LEASE_CONFLICTTrack owned by another lane / master lock
PARSE_FAILdeck invalid
RATE_LIMITToo many lines/sec
AUTHBad token

Skill-gating is enforced today, but not via an error code: the receiver silently skips master-scope lines an actor's skillIds do not permit (src/codj/Skills.tish, src/codj/Merge.tish).

6. Examples

Human line

{ "type": "deck.line", "actorId": "human-xyz", "line": "  mix gain 0.9 pan 0", "authorId": "u1" }

Direct to AI-A (with perf step for scheduling)

{ "type": "direct", "targetActorId": "agent-1", "text": "add euclidean 5/16 hi-hat pattern", "authorId": "u1", "perfStep": 120 }

deck.block scheduled for step 200, must arrive by 180

{
  "type": "deck.block",
  "actorId": "agent-1",
  "authorId": "agent",
  "lines": ["deck 1", "track H id h1 gen noise_burst", "  steps euclid 5 16"],
  "effectivePerfStep": 200,
  "submitDeadlinePerfStep": 180
}