Skip to main content
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

Servers

ServerProtocolHostSecurity
localws127.0.0.1bearerAuth
localSsehttp127.0.0.1bearerAuth

The hosts are the loopback address, as in the HTTP API: the gateway runs on your device and the contract fixes no port.

Authentication

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

/v1/sync

  • Loro Protocol over WebSocket
  • Version 1
  • Ordered
  • Backpressured
  • Server: local

Messages

MessageDirectionSummary
joinBoth waysJoin an authorized Loro room and exchange version state
updateBoth waysBounded standard Loro Protocol update or fragment
ackServer to clientDurable Store acknowledgement
leaveBoth waysHalf-close one logical room
errorServer to clientTerminal room or connection error

The contract names these messages without a payload schema. The HTTP operation above documents the request that opens the stream.

/v1/ai/chats/{chat}/turns

  • Server-sent events
  • Version 1
  • Ordered
  • Backpressured
  • Server: localSse

Messages

MessageDirectionSummary
acceptedServer to clientDurable turn acceptance and retry-safe attempt identities
eventServer to clientOrdered 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.

/v1/ai/providers/ollama/pulls

  • Server-sent events
  • Version 1
  • Ordered
  • Backpressured
  • Server: localSse

Messages

MessageDirectionSummary
acceptedServer to clientAccepted Ollama model pull
eventServer to clientNormalized 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.

/v1/sessions/{session_id}/subscribe

  • Server-sent events
  • Version 1
  • Ordered
  • Backpressured
  • Explicit gap records
  • Scope: sessions.output.read
  • Capability: sessions
  • Server: localSse

Messages

MessageDirectionSummary
session_stream_itemServer to clientPer-source sequenced event/output, explicit resnapshot gap, or terminal close

session_stream_item payload

One of 4 shapes:

  1. kind: "event"

    FieldTypeDescription
    eventrequiredSequencedSessionEvent
    kindrequired"event"
  2. kind: "output"

    FieldTypeDescription
    chunkrequiredRawOutputChunk

    One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume RenderUpdate instead.

    kindrequired"output"
  3. kind: "gap"

    FieldTypeDescription
    sourcerequiredSessionStreamSource
    expectedrequiredStreamSequence
    actualrequiredStreamSequence
    resnapshot_requiredrequiredboolean
    kindrequired"gap"
  4. kind: "closed"

    FieldTypeDescription
    errorSessionFailure or null
    kindrequired"closed"
Example session_stream_item event
{
  "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.

Payload schemas

The schemas the channels' payloads use. Each is the same as the HTTP API schema of the same name.

SessionStreamItem

One of 4 shapes:

  1. kind: "event"

    FieldTypeDescription
    eventrequiredSequencedSessionEvent
    kindrequired"event"
  2. kind: "output"

    FieldTypeDescription
    chunkrequiredRawOutputChunk

    One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume RenderUpdate instead.

    kindrequired"output"
  3. kind: "gap"

    FieldTypeDescription
    sourcerequiredSessionStreamSource
    expectedrequiredStreamSequence
    actualrequiredStreamSequence
    resnapshot_requiredrequiredboolean
    kindrequired"gap"
  4. kind: "closed"

    FieldTypeDescription
    errorSessionFailure or null
    kindrequired"closed"

SessionStreamItem in the HTTP API reference

SequencedSessionEvent

FieldTypeDescription
session_idrequiredTerminalSessionId
sequencerequiredStreamSequence
eventrequiredSessionEvent

Lifecycle and low-volume facts for one session. Render content has its own bounded [crate::RenderUpdate] stream.

SequencedSessionEvent in the HTTP API reference

TerminalSessionId

Type TerminalSessionId

TerminalSessionId in the HTTP API reference

StreamSequence

Type StreamSequence

StreamSequence in the HTTP API reference

SessionEvent

Lifecycle and low-volume facts for one session. Render content has its own bounded [crate::RenderUpdate] stream.

One of 14 shapes:

  1. kind: "commands_updated"

    Protocol v23. The live session's current command listing, including an authoritative empty listing.

    FieldTypeDescription
    commandsrequiredarray of AgentCommand
    kindrequired"commands_updated"
  2. kind: "output"

    FieldTypeDescription
    byte_countrequiredinteger (uint64, >= 0)
    kindrequired"output"
  3. kind: "bell"

    FieldTypeDescription
    kindrequired"bell"
  4. kind: "started"

    FieldTypeDescription
    kindrequired"started"
  5. kind: "exited"

    FieldTypeDescription
    codeinteger (int32) or null
    kindrequired"exited"
  6. kind: "failed"

    FieldTypeDescription
    errorrequiredSessionFailure

    A content-free developer diagnostic. UI maps code to localized copy.

    kindrequired"failed"
  7. kind: "working_directory_changed"

    FieldTypeDescription
    working_directoryrequiredstring
    kindrequired"working_directory_changed"
  8. kind: "title_changed"

    FieldTypeDescription
    titlerequiredstring
    kindrequired"title_changed"
  9. kind: "attention_changed"

    FieldTypeDescription
    attentionrequiredAttentionState
    kindrequired"attention_changed"
  10. kind: "attachment_created"

    FieldTypeDescription
    attachment_idrequiredAttachmentId
    kindrequired"attachment_created"
  11. kind: "attachment_removed"

    FieldTypeDescription
    attachment_idrequiredAttachmentId
    kindrequired"attachment_removed"
  12. kind: "attachment_rejected"

    FieldTypeDescription
    attachment_idrequiredAttachmentId
    coderequiredErrorCode

    Stable error token; unknown values remain errors.

    kindrequired"attachment_rejected"
  13. kind: "attachment_delivered"

    FieldTypeDescription
    attachment_idrequiredAttachmentId
    turn_idrequiredAgentTurnId
    kindrequired"attachment_delivered"
  14. 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.

    FieldTypeDescription
    handoverrequiredHandoverState

    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"

SessionEvent in the HTTP API reference

AgentCommand

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.

FieldTypeDescription
namerequiredstring
descriptionstring
display_namestring or null
kindrequiredAgentCommandKind

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]).

input_hintstring 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 input.hint.

AgentCommand in the HTTP API reference

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 ([AgentCommandKind::group]).

One of 5 shapes:

  1. Variant 1

    An ACP available_commands_update entry invoked by /name.

    "command"

  2. Variant 2

    A skill of the folder the agent works in (Codex's repo scope).

    "repo_skill"

  3. Variant 3

    A skill of the person's own (user).

    "user_skill"

  4. Variant 4

    A skill the agent ships with (system).

    "system_skill"

  5. Variant 5

    A skill an administrator installed (admin).

    "admin_skill"

AgentCommandKind in the HTTP API reference

SessionFailure

A content-free developer diagnostic. UI maps code to localized copy.

FieldTypeDescription
coderequiredErrorCode

Stable error token; unknown values remain errors.

messagerequiredstring

SessionFailure in the HTTP API reference

ErrorCode

Stable error token; unknown values remain errors.

Type ErrorCode

ErrorCode in the HTTP API reference

AttentionState

FieldTypeDescription
unread_countrequiredinteger (uint32, >= 0)
requires_userrequiredboolean
reasonAttentionReason or null

AttentionState in the HTTP API reference

AttentionReason

Type AttentionReason

AttentionReason in the HTTP API reference

AttachmentId

Type AttachmentId

AttachmentId in the HTTP API reference

AgentTurnId

Type AgentTurnId

AgentTurnId in the HTTP API reference

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.

One of 5 shapes:

  1. Variant 1

    "idle"

  2. Variant 2

    Someone asked while a controller was held; the holder has been told.

    "requested"

  3. Variant 3

    The holder released its lease for the handover; the next attach takes it.

    "released"

  4. Variant 4

    The lease was granted after a release: a person holds the session.

    "taken"

  5. Variant 5

    The person gave the lease back, or lost it; the next attach reclaims.

    "returned"

HandoverState in the HTTP API reference

RawOutputChunk

One bounded chunk for an explicitly authorized non-visual output subscription. Render subscribers consume RenderUpdate instead.

FieldTypeDescription
session_idrequiredTerminalSessionId
sequencerequiredStreamSequence
bytesrequiredarray of integer (uint8, >= 0, <= 255)

RawOutputChunk in the HTTP API reference

SessionStreamSource

Type SessionStreamSource

SessionStreamSource in the HTTP API reference

HTTP API reference (OpenAPI) Every endpoint of the Koru API gateway on your device: methods, parameters, request and response bodies, scopes and errors, from its OpenAPI contract.

Generated from contract version 1.0.0. Last updated .

Privacy choices

Choose which optional tools Koru may use on this site. Your choice is saved in a cookie in this browser for 12 months. Privacy policy

Privacy choices

Keep you signed in, protect forms and remember your language and this choice.

Always on

PostHog and Google Analytics 4 measure page views and actions such as downloads, using cookies or local storage.

PostHog records how pages are used, with form inputs masked and private pages excluded. Needs Analytics.

Ahrefs Web Analytics measures visits and where they come from, and Google Ads measures whether our ads led to a visit or download.