One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume RenderUpdate instead.
API reference sections
Streaming API reference
Koru streams
The Koru API gateway streams over two protocols: server-sent events over HTTP, and the standard Loro Protocol over a WebSocket at /v1/sync. Every channel is ordered and backpressured. Session streams use explicit, independent cursors and gap records.
This reference is generated from the gateway's AsyncAPI contract. The HTTP requests that open each stream are in the HTTP API reference.
4 channels · 16 payload schemas · AsyncAPI 3.0.0 · Koru API Gateway streams, version 1.0.0
| Server | Protocol | Host | Security |
|---|---|---|---|
| local | ws | 127.0.0.1 | bearerAuth |
| localSse | http | 127.0.0.1 | bearerAuth |
The hosts are the loopback address, as in the HTTP API: the gateway runs on your device and the contract fixes no port.
Every server is secured by bearerAuth, which the contract declares as a key in the Authorization header: the header the HTTP API's bearer token travels in.
bearerAuth: type httpApiKey, in header, name Authorization.
Channels
- Loro Protocol over WebSocket
- Version 1
- Ordered
- Backpressured
- Server: local
Opened over HTTP by
Messages
| Message | Direction | Summary |
|---|---|---|
| join | Both ways | Join an authorized Loro room and exchange version state |
| update | Both ways | Bounded standard Loro Protocol update or fragment |
| ack | Server to client | Durable Store acknowledgement |
| leave | Both ways | Half-close one logical room |
| error | Server to client | Terminal room or connection error |
The contract names these messages without a payload schema. The HTTP operation above documents the request that opens the stream.
- Server-sent events
- Version 1
- Ordered
- Backpressured
- Server: localSse
Opened over HTTP by
Messages
| Message | Direction | Summary |
|---|---|---|
| accepted | Server to client | Durable turn acceptance and retry-safe attempt identities |
| event | Server to client | Ordered normalized Koru AI stream event |
The contract names these messages without a payload schema. The HTTP operation above documents the request that opens the stream.
- Server-sent events
- Version 1
- Ordered
- Backpressured
- Server: localSse
Opened over HTTP by
Messages
| Message | Direction | Summary |
|---|---|---|
| accepted | Server to client | Accepted Ollama model pull |
| event | Server to client | Normalized progress followed by one completed, failed, or cancelled event |
The contract names these messages without a payload schema. The HTTP operation above documents the request that opens the stream.
- Server-sent events
- Version 1
- Ordered
- Backpressured
- Explicit gap records
- Scope: sessions.output.read
- Capability: sessions
- Server: localSse
Opened over HTTP by
Messages
| Message | Direction | Summary |
|---|---|---|
| session_stream_item | Server to client | Per-source sequenced event/output, explicit resnapshot gap, or terminal close |
session_stream_item payload
One of 4 shapes:
kind: "event"
Field Type Description eventrequired SequencedSessionEvent kindrequired "event" kind: "output"
Field Type Description chunkrequired RawOutputChunk kindrequired "output" kind: "gap"
Field Type Description sourcerequired SessionStreamSource expectedrequired StreamSequence actualrequired StreamSequence resnapshot_requiredrequired boolean kindrequired "gap" kind: "closed"
Field Type Description error SessionFailure or null kindrequired "closed"
{
"event": {
"session_id": "00000000-0000-4000-8000-000000000000",
"sequence": 1,
"event": {
"commands": [
{
"name": "string",
"description": "string",
"display_name": "string",
"kind": "command",
"input_hint": "string"
}
],
"kind": "commands_updated"
}
},
"kind": "event"
}The contract has no example values, so example bodies are generated from each schema: every field is shown with a placeholder of its type.
The schemas the channels' payloads use. Each is the same as the HTTP API schema of the same name.
One of 4 shapes:
kind: "event"
Field Type Description eventrequired SequencedSessionEvent kindrequired "event" kind: "output"
Field Type Description chunkrequired RawOutputChunk One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume
RenderUpdateinstead.kindrequired "output" kind: "gap"
Field Type Description sourcerequired SessionStreamSource expectedrequired StreamSequence actualrequired StreamSequence resnapshot_requiredrequired boolean kindrequired "gap" kind: "closed"
Field Type Description error SessionFailure or null kindrequired "closed"
| Field | Type | Description |
|---|---|---|
| session_idrequired | TerminalSessionId | |
| sequencerequired | StreamSequence | |
| eventrequired | SessionEvent | Lifecycle and low-volume facts for one session. Render content has its own bounded [ |
Type TerminalSessionId
Type StreamSequence
Lifecycle and low-volume facts for one session. Render content has its own bounded [crate::RenderUpdate] stream.
One of 14 shapes:
kind: "commands_updated"
Protocol v23. The live session's current command listing, including an authoritative empty listing.
Field Type Description commandsrequired array of AgentCommand kindrequired "commands_updated" kind: "output"
Field Type Description byte_countrequired integer (uint64, >= 0) kindrequired "output" kind: "bell"
Field Type Description kindrequired "bell" kind: "started"
Field Type Description kindrequired "started" kind: "exited"
Field Type Description code integer (int32) or null kindrequired "exited" kind: "failed"
Field Type Description errorrequired SessionFailure A content-free developer diagnostic. UI maps
codeto localized copy.kindrequired "failed" kind: "working_directory_changed"
Field Type Description working_directoryrequired string kindrequired "working_directory_changed" kind: "title_changed"
Field Type Description titlerequired string kindrequired "title_changed" kind: "attention_changed"
Field Type Description attentionrequired AttentionState kindrequired "attention_changed" kind: "attachment_created"
Field Type Description attachment_idrequired AttachmentId kindrequired "attachment_created" kind: "attachment_removed"
Field Type Description attachment_idrequired AttachmentId kindrequired "attachment_removed" kind: "attachment_rejected"
Field Type Description attachment_idrequired AttachmentId coderequired ErrorCode Stable error token; unknown values remain errors.
kindrequired "attachment_rejected" kind: "attachment_delivered"
Field Type Description attachment_idrequired AttachmentId turn_idrequired AgentTurnId kindrequired "attachment_delivered" kind: "handover_changed"
Protocol v14. The controller handover moved: someone asked, the holder released, the lease was taken, or it was given back. A new tag, so a host never sends it to a peer that negotiated less than v14.
Field Type Description handoverrequired HandoverState Where a controller handover stands.
Release, not preemption: nothing takes a lease from its holder. The holder is asked, releases at a boundary of its choosing, the requester attaches, and gives it back the same way. Each step is a state a reader can see and an event a subscriber receives.
kindrequired "handover_changed"
One entry an agent offers. name is what the person's message says and what goes back; description is one line about it, empty when the agent gave none; display_name is the agent's own name to show, when it gives one.
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| description | string | |
| display_name | string or null | |
| kindrequired | AgentCommandKind | Where an entry comes from: the folder's own, the person's, what the agent ships, what an administrator set. A picker lists the first two groups first and the last two together ([ |
| input_hint | string or null | What the entry takes after its name, in the agent's words, when it says. No skill has one; it is the ACP command's |
Where an entry comes from: the folder's own, the person's, what the agent ships, what an administrator set. A picker lists the first two groups first and the last two together ([AgentCommandKind::group]).
One of 5 shapes:
Variant 1
An ACP
available_commands_updateentry invoked by/name."command"
Variant 2
A skill of the folder the agent works in (Codex's
reposcope)."repo_skill"
Variant 3
A skill of the person's own (
user)."user_skill"
Variant 4
A skill the agent ships with (
system)."system_skill"
Variant 5
A skill an administrator installed (
admin)."admin_skill"
A content-free developer diagnostic. UI maps code to localized copy.
| Field | Type | Description |
|---|---|---|
| coderequired | ErrorCode | Stable error token; unknown values remain errors. |
| messagerequired | string |
Stable error token; unknown values remain errors.
Type ErrorCode
| Field | Type | Description |
|---|---|---|
| unread_countrequired | integer (uint32, >= 0) | |
| requires_userrequired | boolean | |
| reason | AttentionReason or null |
Type AttentionReason
Type AttachmentId
Type AgentTurnId
Where a controller handover stands.
Release, not preemption: nothing takes a lease from its holder. The holder is asked, releases at a boundary of its choosing, the requester attaches, and gives it back the same way. Each step is a state a reader can see and an event a subscriber receives.
One of 5 shapes:
Variant 1
"idle"
Variant 2
Someone asked while a controller was held; the holder has been told.
"requested"
Variant 3
The holder released its lease for the handover; the next attach takes it.
"released"
Variant 4
The lease was granted after a release: a person holds the session.
"taken"
Variant 5
The person gave the lease back, or lost it; the next attach reclaims.
"returned"
One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume RenderUpdate instead.
| Field | Type | Description |
|---|---|---|
| session_idrequired | TerminalSessionId | |
| sequencerequired | StreamSequence | |
| bytesrequired | array of integer (uint8, >= 0, <= 255) |
Type SessionStreamSource
Generated from contract version 1.0.0. Last updated .
