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:
RootState {
agents: AgentInfo[]
activeSessions?: number
terminals?: TerminalInfo[]
config?: RootConfigState
}agents— agent backends the server can speak to, including anyprotectedResourcesthey 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. Supplylimitto bound the page size. - If the result includes a
nextCursor, more entries exist — pass it back ascursoron the next call to fetch the following page. - A missing
nextCursorsignals 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://")
| Method | Kind | Why it belongs on root |
|---|---|---|
initialize | request | Connection-level handshake command; scoped to the root channel. |
ping | request | Connection liveness check; scoped to the root channel. |
reconnect | request | Connection resume/replay negotiation; scoped to the root channel. |
listSessions | request | Session catalogue lives on root (root/session* events keep the cache fresh). |
resourceRead | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client to fetch from a client-published URI. |
resourceWrite | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client for host-driven per-session FS providers. |
resourceList | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client. |
resourceCopy | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client. |
resourceDelete | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client. |
resourceMove | request | Filesystem/content access is connection-level, not session-local. May also be issued server → client. |
resourceResolve | request | stat + realpath combination; throws NotFound for missing URIs. May also be issued server → client. |
resourceMkdir | request | mkdir -p semantics. May also be issued server → client. |
resourceRequest | request | Permission grant/revocation flow is connection-level. Symmetrical: either peer MAY initiate. |
createResourceWatch | request | Opens 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. |
authenticate | request | Bearer-token push for protected resources is connection-level. |
resolveSessionConfig | request | Pre-creation config resolution happens before any session channel exists. |
sessionConfigCompletions | request | Completes dynamic fields in pre-creation session config. |
Notifications (params.channel = "ahp-root://")
| Method | Kind | Meaning |
|---|---|---|
action | server → client notification | Root-scoped action envelope (root/* action payloads). |
root/sessionAdded | server → client notification | Session catalogue entry created. |
root/sessionRemoved | server → client notification | Session catalogue entry removed. |
root/sessionSummaryChanged | server → client notification | Session catalogue entry mutated. |
root/progress | server → client notification | Generic progress for a long-running operation a client opted into (e.g. an SDK download). |
unsubscribe | client → server notification | Stop receiving root-channel messages. |
dispatchAction | client → server notification | Dispatch 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:
| Action | Direction | Reducer effect |
|---|---|---|
root/agentsChanged | Server | Replaces agents |
root/activeSessionsChanged | Server | Replaces activeSessions |
root/terminalsChanged | Server | Replaces terminals |
root/configChanged | Server / Client | Merges (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.
{
"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.
{
"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.
{
"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.
{
"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.