Skip to content

Root Channel

The root channel is the top-level channel every AHP server exposes. It carries global state — the agents the server provides, the terminals it manages, and host-level configuration — plus the catalogue events for sessions.

URI

ahp-root://

Exactly one root channel exists per server. Clients SHOULD subscribe to it during the handshake via initialSubscriptions to receive the agent list, terminal list, and host config in the same round-trip.

State

Subscribers receive a RootState snapshot:

typescript
RootState {
  agents: AgentInfo[]
  activeSessions?: number
  terminals?: TerminalInfo[]
  config?: RootConfigState
}
  • agents — agent backends the server can speak to, including any protectedResources they require for authentication. See Authentication.
  • activeSessions — count of non-disposed sessions. Lightweight badge counter.
  • terminals — lightweight per-terminal metadata for rendering a terminal manager UI without subscribing to every terminal. See Terminal Channel for the full state.
  • config — host-level configuration schema and current values.

The session list is not part of root state. Clients fetch it imperatively via listSessions and patch it from root/* notifications described below.

Paginating the catalogue

A large catalogue can be fetched incrementally. listSessions accepts an optional limit (the maximum number of entries the client wants in the page — the server SHOULD respect it, but MAY return fewer and MAY impose its own upper cap) and an optional opaque cursor. The result carries the page in items plus an optional nextCursor:

  • To fetch the first page, omit cursor. Supply limit to bound the page size.
  • If the result includes a nextCursor, more entries exist — pass it back as cursor on the next call to fetch the following page.
  • A missing nextCursor signals the end of the catalogue.

The cursor is opaque and server-defined: the server picks the ordering and keyset. Clients MUST NOT parse, modify, or persist a cursor across connections. An unrecognised cursor SHOULD be rejected with an InvalidParams error. The server SHOULD return most-recently-modified entries first, so the first page is the immediately useful one.

Pagination is fully additive. A client that omits limit/cursor and ignores nextCursor sees the pre-pagination behaviour (subject to any server-imposed cap), and a server that does not paginate ignores the inputs and returns everything in one page. Pagination governs only the initial and backfill fetches — the root/session* notifications keep an already-loaded page live exactly as before.

Methods and events on this channel

This section lists wire methods that are interpreted in the context of ahp-root://. If params.channel is some other URI, they are handled by the target channel instead.

Commands (params.channel = "ahp-root://")

MethodKindWhy it belongs on root
initializerequestConnection-level handshake command; scoped to the root channel.
pingrequestConnection liveness check; scoped to the root channel.
reconnectrequestConnection resume/replay negotiation; scoped to the root channel.
listSessionsrequestSession catalogue lives on root (root/session* events keep the cache fresh).
resourceReadrequestFilesystem/content access is connection-level, not session-local. May also be issued server → client to fetch from a client-published URI.
resourceWriterequestFilesystem/content access is connection-level, not session-local. May also be issued server → client for host-driven per-session FS providers.
resourceListrequestFilesystem/content access is connection-level, not session-local. May also be issued server → client.
resourceCopyrequestFilesystem/content access is connection-level, not session-local. May also be issued server → client.
resourceDeleterequestFilesystem/content access is connection-level, not session-local. May also be issued server → client.
resourceMoverequestFilesystem/content access is connection-level, not session-local. May also be issued server → client.
resourceResolverequeststat + realpath combination; throws NotFound for missing URIs. May also be issued server → client.
resourceMkdirrequestmkdir -p semantics. May also be issued server → client.
resourceRequestrequestPermission grant/revocation flow is connection-level. Symmetrical: either peer MAY initiate.
createResourceWatchrequestOpens a file-change watcher; the receiver returns an ahp-resource-watch:/<id> channel. May also be issued server → client to watch a client-side URI. The watcher is released when subscribers unsubscribe — no explicit dispose call.
authenticaterequestBearer-token push for protected resources is connection-level.
resolveSessionConfigrequestPre-creation config resolution happens before any session channel exists.
sessionConfigCompletionsrequestCompletes dynamic fields in pre-creation session config.

Notifications (params.channel = "ahp-root://")

MethodKindMeaning
actionserver → client notificationRoot-scoped action envelope (root/* action payloads).
root/sessionAddedserver → client notificationSession catalogue entry created.
root/sessionRemovedserver → client notificationSession catalogue entry removed.
root/sessionSummaryChangedserver → client notificationSession catalogue entry mutated.
root/progressserver → client notificationGeneric progress for a long-running operation a client opted into (e.g. an SDK download).
unsubscribeclient → server notificationStop receiving root-channel messages.
dispatchActionclient → server notificationDispatch a root-scoped client action (currently root/configChanged).

auth/required may also be emitted on ahp-root:// when the auth requirement is root-scoped; see Authentication.

Actions

Root state is mutated by action envelopes broadcast on this channel. Refer to the Root Channel Reference for the full list; the root-scoped actions are:

ActionDirectionReducer effect
root/agentsChangedServerReplaces agents
root/activeSessionsChangedServerReplaces activeSessions
root/terminalsChangedServerReplaces terminals
root/configChangedServer / ClientMerges (or replaces) config.values

All root-scoped action envelopes have channel: "ahp-root://".

Protocol Notifications

In addition to action envelopes, the server pushes per-session catalogue events to subscribers of ahp-root://. These notifications keep cached session lists in sync without subscribing to every session URI individually.

root/sessionAdded

Emitted when a new session is created.

json
{
  "jsonrpc": "2.0",
  "method": "root/sessionAdded",
  "params": {
    "channel": "ahp-root://",
    "summary": {
      "resource": "ahp-session:/<uuid>",
      "title": "New Session",
      "status": 1,
      "createdAt": "2024-03-09T16:00:00.000Z",
      "modifiedAt": "2024-03-09T16:00:00.000Z"
    }
  }
}

root/sessionRemoved

Emitted when a session is disposed.

json
{
  "jsonrpc": "2.0",
  "method": "root/sessionRemoved",
  "params": {
    "channel": "ahp-root://",
    "session": "ahp-session:/<uuid>"
  }
}

root/sessionSummaryChanged

Emitted when any mutable field on an existing SessionSummary changes (title, status, modifiedAt, working directory, read/done state, change statistics, …). Only the changed fields are carried; identity fields (resource, provider, createdAt) never change and MUST be omitted.

json
{
  "jsonrpc": "2.0",
  "method": "root/sessionSummaryChanged",
  "params": {
    "channel": "ahp-root://",
    "session": "ahp-session:/<uuid>",
    "changes": {
      "title": "Refactor auth middleware",
      "status": 8,
      "modifiedAt": "2024-03-09T16:02:03.456Z"
    }
  }
}

Servers MAY coalesce or debounce this notification for noisy fields — for example, rapid modifiedAt bumps during a streaming turn, or frequent changes updates during an edit burst. Clients that have no cached entry for session MAY ignore the notification.

Like all protocol notifications, the root/* events are ephemeral and are not replayed on reconnect. After reconnecting, clients SHOULD re-fetch the catalogue via listSessions.

Progress

The server MAY emit root/progress to report incremental progress on a long-running operation a client opted into — most notably the lazy, first-use download of an agent's native SDK. A client opts in by supplying a progressToken on the originating request (today the progressToken field of createSession); the server echoes that token on every frame so the client can correlate progress back to the call and the UI awaiting it. The notification is operation-agnostic — it names no domain object.

json
{
  "jsonrpc": "2.0",
  "method": "root/progress",
  "params": {
    "channel": "ahp-root://",
    "progressToken": "9b2c1f7e-4a0d-4e2b-8b1a-2f7e4a0d4e2b",
    "progress": 18874368,
    "total": 41957498,
    "message": "Downloading Claude agent…"
  }
}

progress is monotonically non-decreasing for a given progressToken. total is present only when the magnitude is known up front (e.g. a Content-Length); when absent, clients SHOULD show an indeterminate indicator. The operation is complete when progress === total — the server MUST emit a final frame satisfying this, setting total to the final progress when the total was never known, after which no further frames reference the token. An optional message carries a human-readable description of the work in progress; a client that tracks the token renders its own (localized) label and MAY ignore it, while a generic client MAY display message verbatim. The server MAY emit no progress at all (for example when the work was already done), in which case the client simply never shows an indicator. Like the catalogue events, root/progress is ephemeral and is not replayed on reconnect.

Authentication Events

The server MAY emit auth/required on the root channel when an agent's protected resource needs (re-)authentication. See Authentication for the full flow.

Released under the MIT License.