Protocol
Transport-facing contract and invariants between Acolyte client and server.
Goal
Define the stable request/response contract between client and server so transport can evolve without changing lifecycle behavior.
Contract shape
- Request: one task payload (
message,history,sessionId, runtime options). - Stream: ordered event sequence for progress and tool activity.
- Final reply: single terminal payload with assistant output and usage metadata.
Event model
Events are append-only and ordered per request.
status: lifecycle/status updates for UI progressreasoning: optional model reasoning texttool-call: tool invocation start (id, name, args)tool-output: incremental tool output for the call idtool-result: tool completion (success/error, structured error detail)text-delta: assistant text stream chunksusage: token usage for the current generation stepchecklist: inline task checklist with group ID, title, and itemserror: terminal stream error
Invariants
- Every request completes with either a
chat.doneorchat.errorRPC message. tool-output/tool-resultreference a priortool-callid.- Unknown event fields are ignored by clients (forward compatibility).
- Error detail payloads are structured and stable.
Versioning
- The protocol is versioned and negotiated by capability handshake.
- Additive changes are preferred; breaking changes require version bump.
Transport stance
- Transport is an implementation detail.
- HTTP+SSE and WebSocket RPC are both supported.
- New transports must preserve this contract and ordering guarantees.
RPC baseline (WebSocket)
RPC uses JSON envelopes with transport request id (rpc_*), type, and optional payload.
Domain task ids are separate (task_*).
Authentication:
- HTTP endpoints use
Authorization: Bearer <apiKey>. - WebSocket RPC uses Bearer auth via
sec-websocket-protocol(bearer.<apiKey>).
Client methods:
status.getchat.start(request payload)chat.abort(request id)task.status(task id)
Server responses:
status.resultchat.accepted(includestaskId)chat.queuedchat.startedchat.eventchat.donechat.error(may includeerrorId)chat.abort.resulttask.status.resulterror
Queue semantics:
- Only one chat request runs per connection at a time.
- Additional
chat.startrequests are accepted and reported aschat.queuedwith a 1-based position. - Queue positions are re-emitted on queue changes (abort/dequeue) so clients can keep ordering accurate.
chat.aborttargets request id, while task lifecycle/state uses task id.