Skip to content

WebSocket Protocol Reference ​

All live gateway traffic uses JSON text frames over GET /ws.

The current protocol is syscall-based:

  • requests carry a syscall name in call
  • responses carry success data in data
  • signals carry async events in signal

The source of truth is:

  • gateway/src/protocol/frames.ts
  • shared/protocol/src/syscalls/system.ts
  • gateway/src/kernel/connect.ts
  • gateway/src/kernel/dispatch.ts

For syscall arguments, result shapes, and domain behavior, see Syscalls Reference.


Frame Types ​

Request Frame ​

json
{
  "type": "req",
  "id": "uuid",
  "call": "sys.connect",
  "args": {}
}
FieldTypeRequiredDescription
type"req"YesRequest discriminator
idstringYesRequest/response correlation ID
callstringYesSyscall name
argsobjectNoSyscall arguments

Response Frame ​

Success:

json
{
  "type": "res",
  "id": "uuid",
  "ok": true,
  "data": {}
}

Error:

json
{
  "type": "res",
  "id": "uuid",
  "ok": false,
  "error": {
    "code": 500,
    "message": "failure"
  }
}
FieldTypeRequiredDescription
type"res"YesResponse discriminator
idstringYesMatching request ID
okbooleanYesSuccess flag
dataunknownNoPresent when ok is true
errorErrorShapeNoPresent when ok is false

Signal Frame ​

json
{
  "type": "sig",
  "signal": "chat.complete",
  "payload": {},
  "seq": 1
}
FieldTypeRequiredDescription
type"sig"YesSignal discriminator
signalstringYesSignal/event name
payloadunknownNoSignal payload
seqnumberNoOptional sequence number

ErrorShape ​

json
{
  "code": 401,
  "message": "Authentication required",
  "details": {},
  "retryable": false
}
FieldTypeRequiredDescription
codenumberYesError code
messagestringYesHuman-readable message
detailsunknownNoStructured error context
retryablebooleanNoRetry hint

Connection Lifecycle ​

  1. Open a websocket to GET /ws.
  2. Send sys.connect as the first request.
  3. Wait for a normal success response or a structured error.
  4. After connect succeeds, exchange syscall requests, responses, and signals until the socket closes.

The gateway rejects setup-mode connections with error code 425 and details:

json
{
  "setupMode": true,
  "next": "sys.setup"
}

sys.connect ​

sys.connect is the handshake syscall. It authenticates the caller, assigns identity, registers drivers or services, and returns the allowed syscall/signal surface.

Request ​

json
{
  "type": "req",
  "id": "uuid",
  "call": "sys.connect",
  "args": {
    "protocol": 1,
    "client": {
      "id": "client-123",
      "version": "0.1.0",
      "platform": "linux",
      "role": "user"
    },
    "auth": {
      "username": "alice",
      "password": "secret"
    }
  }
}
FieldTypeRequiredDescription
protocolnumberYesMust currently be 1
client.idstringYesClient identifier
client.versionstringYesClient version
client.platformstringYesPlatform string
client.role"user" | "driver" | "service"YesConnection role
client.channelstringNoRequired for service role
driver.implementsstring[]NoRequired for driver role
auth.usernamestringNoRequired when authenticating
auth.passwordstringNoUser-password auth
auth.tokenstringNoToken auth. Required for machine connections.

Response ​

json
{
  "type": "res",
  "id": "uuid",
  "ok": true,
  "data": {
    "protocol": 1,
    "server": {
      "version": "dev",
      "connectionId": "conn-123"
    },
    "identity": {
      "role": "user",
      "process": {
        "uid": 1000,
        "gid": 1000,
        "gids": [1000],
        "username": "alice",
        "home": "/home/alice",
        "cwd": "/home/alice",
        "workspaceId": null
      },
      "capabilities": ["fs.*", "proc.*"]
    },
    "syscalls": ["fs.read", "proc.send"],
    "signals": ["chat.text", "chat.complete"]
  }
}

Role-specific identity payloads

RoleExtra fields
usernone
driverdevice, implements
servicechannel

Syscall Dispatch ​

The websocket protocol is uniform: every operation is a req frame with a syscall name in call. Dispatch behavior depends on the syscall domain:

DomainBehavior
fs.*Native on gsv, or routed to a driver when args.target names a device
shell.execNative on gsv, routed to a driver when args.target names a device, or routed by args.sessionId for an existing shell session
proc.*Kernel and Process DO control plane
pkg.*, repo.*, sys.*, sched.*, notification.*, signal.*Kernel-handled
adapter.*Service-binding / adapter control path
ai.*Kernel-internal process bootstrap path

For routed fs.* and initial shell.exec requests, the gateway strips args.target before forwarding the request frame to the driver. Shell continuations use args.sessionId; the gateway looks up the session owner and forwards the same shell.exec frame to that device.

Use the Syscalls Reference for the full syscall surface.


Signals ​

The connect response advertises the signal set allowed for the role.

Current role defaults from buildSignalList():

User connections ​

  • process.message
  • process.context
  • chat.text
  • chat.tool_call
  • chat.tool_result
  • chat.hil
  • chat.complete
  • process.exit
  • device.status
  • adapter.status
  • pkg.changed

Driver connections ​

  • device.status

Service connections ​

  • adapter.status

chat.* signals are emitted by Process DOs and relayed through run-route tracking. In the current kernel:

  • user connections receive routed chat.* signals for their own runs
  • adapter surfaces only use chat.hil and chat.complete

Binary Frames ​

Binary-frame helpers still exist in the CLI protocol module, using this format:

text
[4 bytes little-endian transfer id][raw chunk bytes]

That code is marked legacy/future-use in cli/src/protocol.rs. The current gateway syscall surface in this repo does not expose a public transfer syscall, so ordinary runtime traffic is JSON text frames only.

See also ​