Skip to content

Routing Reference

GSV routing is kernel-level message and syscall routing. It is not only chat/session routing. The Kernel Durable Object is the central router for WebSocket clients, agent processes, package apps, adapter workers, and connected devices.

Routing Surfaces

SurfaceEntry PointRouted ByDestination
CLI or browser clientWebSocket request framesyscall name, caller capabilities, optional targetKernel handler, Process DO, or device driver
Agent processKernel.recvFrame(pid, frame)process identity and syscallKernel handler or device driver
Package appKernel.appRequest(...)app frame, package manifest, entrypoint grantsKernel handler or device driver
Adapter workeradapter.inbound syscalllinked actor identity and surface routeUser init process or routed process
Device driverWebSocket response framepersisted route idOriginal client, process, or app

All requests use the same frame shape:

json
{
  "type": "req",
  "id": "call-id",
  "call": "fs.read",
  "args": { "path": "/home/alice/context.d/00-role.md" }
}

Syscall Routing

The dispatcher first checks args.target. If target is omitted or set to gsv, the syscall is handled natively by the Kernel. If target names a connected device and the syscall is routable, the Kernel forwards it to that device.

Only fs.* and shell.exec support device routing. Other domains such as sys.*, proc.*, pkg.*, repo.*, adapter.*, and notification.* are kernel-internal.

json
{ "path": "/etc/passwd", "target": "gsv" }
json
{ "input": "git status --short", "cwd": "~/projects/gsv", "target": "laptop" }

Before forwarding to a device, the Kernel checks:

  • The caller can access the device by ownership, group ACL, or root.
  • The device is online.
  • The device advertises an implements capability matching the syscall.
  • A live driver WebSocket exists for the device id.

Forwarded calls are stored in the Kernel SQLite routing_table with the call id, syscall, origin, target device, and timeout schedule. When the device responds, the Kernel consumes the route and returns the response to the original origin. If the route expires first, the origin receives a 504 timeout response.

Shell continuations use a second durable session mapping. A routed shell start that returns status: "running" records its sessionId and owning device. Later shell.exec requests with that sessionId route to the same device even when target is omitted. This keeps the model-facing Shell tool small while preventing long-running commands from depending on one in-flight route.

codemode.exec is different: the Kernel exposes it as an agent tool, but the Process DO executes it locally with the Worker Loader instead of routing it through the Kernel dispatcher. The manual codemode.run syscall is public and kernel-forwarded to a Process DO, which uses the same executor. CodeMode's in-block shell(...) and fs.*(...) helpers call back into the Process, which then dispatches normal shell.exec and fs.* request frames through the Kernel. That means nested CodeMode calls still use the same device routing, approval policy for agent tool calls, async response, and shell session behavior as direct model tool calls.

Process Routing

Agent conversations are durable processes, identified by PIDs. The long-lived home process for a user is init:{uid}. Other processes are spawned with proc.spawn and usually receive UUID PIDs.

The Kernel stores process metadata in the processes table: uid, gids, profile, parent PID, cwd, source mounts, activity state, active run/conversation ids, queued count, label, and context files. proc.list is answered directly from this registry.

These syscalls are forwarded to the target Process DO after ownership checks:

text
proc.send
proc.abort
proc.hil
proc.kill
proc.history
proc.reset
codemode.run

When no PID is supplied, process syscalls default to the caller's init:{uid} process. Non-root callers cannot access another user's process.

Process Signal Routing

Process DOs emit run signals such as proc.run.stream, proc.run.output, proc.run.tool.finished, proc.run.hil.requested, and proc.run.finished. The Kernel routes those signals using run_routes.

For CLI/browser-originated runs, run_routes maps runId to the originating WebSocket connection. For adapter-originated runs, it maps runId to the adapter, account id, surface kind, surface id, and optional thread id. Routes expire after 30 minutes.

If a run route is missing, the Kernel falls back to broadcasting the signal to connected clients for the owning uid.

Process DOs also emit proc.changed for durable state changes such as messages, context estimates, queue size, and conversation archive/fork events. The Kernel uses proc.run.* and proc.changed payloads to keep proc.list activity state current.

Adapter Routing

Messaging adapters call adapter.inbound through a service identity. The Kernel normalizes the adapter id and account id, then resolves the external actor id through identity_links.

Inbound behavior:

  • Linked actor: resolve the local uid and deliver to a process.
  • Unlinked DM actor: return a link challenge such as gsv auth link CODE.
  • Unlinked non-DM actor: drop the message as unlinked_actor.

The default delivery target is the user's init:{uid} process. A surface_routes entry can override this for a specific adapter account and surface:

text
adapter + accountId + surface.kind + surface.id -> pid

Human-in-the-loop replies are routed specially. If the target process has a pending HIL request, a DM reply of approval or denial resumes proc.hil instead of starting a new chat turn.

Package App Routing

Package UI and RPC calls are routed through package identity frames. The Kernel verifies:

  • The package is installed and enabled.
  • The route base and entrypoint match the installed manifest.
  • The entrypoint grants the requested syscall.
  • The user identity in the app frame is still valid.

Package app syscalls can use the same device routing path as clients and processes. Async device responses are held in memory as pending app responses until the device reply or timeout arrives.

Device Routing

Devices are persistent records in Kernel SQLite. A driver connection registers a device id, owner uid, owner gid, platform, version, and implements list. The access model is Linux-like:

  • Root can use every device.
  • The owner uid can use the device.
  • Members of granted groups can use the device.

Device routing does not rename syscalls. Agents and clients always see the same syscall names, such as fs.read and shell.exec; target selects whether the initial call runs on gsv or a device. For shell continuations, sessionId selects the previously started shell session.

Failure Behavior

FailureResult
Missing capability403 Permission denied
Device access denied403 Access denied to device
Device offline503 Device offline
No active device connection503 No active connection
Device does not implement syscall400 Device does not implement
Device route timeout504 Syscall timed out
Unknown or foreign processProcess not found or Permission denied
StorePurpose
routing_tableIn-flight device-routed syscalls.
shell_sessionsDevice ownership and lifecycle for resumable shell sessions.
run_routesRoutes process run signals back to connections or adapter surfaces.
processesKernel process registry and process ownership.
devices, device_accessDevice catalog and group ACLs.
identity_linksExternal adapter actor to local uid mapping.
surface_routesAdapter surface to process mapping.