Root Channel
Reference for the ahp-root:// channel — the single, host-wide channel every client subscribes to first. See Root Channel specification for the wire-level overview.
JSON Schema: state.schema.json
State Types
PolicyState
Policy configuration state for a model.
| Member | Value |
|---|---|
Enabled | 'enabled' |
Disabled | 'disabled' |
Unconfigured | 'unconfigured' |
RootState
Global state shared with every client subscribed to ahp-root://.
| Field | Type | Required | Description |
|---|---|---|---|
agents | AgentInfo[] | Yes | Available agent backends and their models |
activeSessions | number | No | Number of active (non-disposed) sessions on the server |
terminals | TerminalInfo[] | No | Known terminals on the server. Subscribe to individual terminal URIs for full state. |
config | RootConfigState | No | Agent host configuration schema and current values |
_meta | Record<string, unknown> | No | Additional implementation-defined metadata about the agent host itself. Clients MAY look for well-known keys here to provide enhanced UI. |
AgentInfo
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | Agent provider ID (e.g. 'copilot') |
displayName | string | Yes | Human-readable name |
description | string | Yes | Description string |
models | SessionModelInfo[] | Yes | Available models for this agent |
protectedResources | ProtectedResourceMetadata[] | No | Protected resources this agent requires authentication for. Each entry describes an OAuth 2.0 protected resource using RFC 9728 semantics. Clients should obtain tokens from the declared authorization_servers and push them via the authenticate command before creating sessions with this agent. |
customizations | Customization[] | No | Customizations associated with this agent. Either container customizations — {@link PluginCustomization | PluginCustomization} entries the agent bundles, plus {@link DirectoryCustomization | DirectoryCustomization} entries it watches in any workspace it's used with — or top-level {@link McpServerCustomization | McpServerCustomization} entries the agent host declares directly. When a session is created with this agent, these entries are augmented (e.g. directory URIs are resolved against the workspace, children are parsed) and propagated into the session's customizations list. |
capabilities | AgentCapabilities | No | Static capabilities the agent advertises about itself. Clients use these to gate features (multi-chat, fork) instead of switching on the provider id. |
AgentCapabilities
Static capabilities an {@link AgentInfo} advertises. Modelled after MCP capabilities: each field is opt-in and its presence (an empty object {}) signals support, while absence means the feature is unsupported and the corresponding client commands MUST NOT be used. Sub-fields carry per-capability options.
| Field | Type | Required | Description |
|---|---|---|---|
multipleChats | MultipleChatsCapability | No | The agent can host more than one concurrent chat per session. When absent, clients MUST NOT call createChat to open chats beyond the default one the session starts with. An empty object {} advertises multi-chat without forking; set {@link MultipleChatsCapability.fork} to also allow forking. |
MultipleChatsCapability
Options for the {@link AgentCapabilities.multipleChats} capability.
| Field | Type | Required | Description |
|---|---|---|---|
fork | boolean | No | The agent can fork a chat from a specific turn. When absent or false, clients MUST NOT pass a {@link ChatForkSource} (source) to createChat. Forking always implies multi-chat support. |
SessionModelInfo
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model identifier |
provider | string | Yes | Provider this model belongs to |
name | string | Yes | Human-readable model name |
maxContextWindow | number | No | Maximum context window size |
maxOutputTokens | number | No | Maximum number of output tokens the model can generate |
maxPromptTokens | number | No | Maximum number of prompt (input) tokens the model accepts |
supportsVision | boolean | No | Whether the model supports vision |
policyState | PolicyState | No | Policy configuration state |
configSchema | ConfigSchema | No | Configuration schema describing model-specific options (e.g. thinking level). Clients present this as a form and pass the resolved values in {@link ModelSelection.config} when creating or changing sessions. |
_meta | Record<string, unknown> | No | Additional provider-specific metadata for this model. Clients MAY look for well-known keys here to provide enhanced UI. For example, a pricing key may carry model pricing metadata. |
ModelSelection
A model selection: the chosen model ID together with any model-specific configuration values whose keys correspond to the model's {@link SessionModelInfo.configSchema}.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Model identifier |
config | Record<string, JsonPrimitive> | No | Model-specific configuration values. Values are JSON primitives: most pickers produce strings, but some (e.g. a numeric context-size picker) produce numbers or booleans, which are carried through as-is. |
RootConfigState
Live agent-host configuration metadata.
The schema describes the available configuration properties and the values contain the current value for each resolved property.
| Field | Type | Description |
|---|---|---|
schema | ConfigSchema | JSON Schema describing available configuration properties |
values | Record<string, unknown> | Current configuration values |
Actions
Mutate RootState. All root actions are server-only.
JSON Schema: actions.schema.json
root/agentsChanged
Fired when available agent backends or their models change.
| Field | Type | Description |
|---|---|---|
type | ActionType.RootAgentsChanged | |
agents | AgentInfo[] | Updated agent list |
root/activeSessionsChanged
Fired when the number of active sessions changes.
| Field | Type | Description |
|---|---|---|
type | ActionType.RootActiveSessionsChanged | |
activeSessions | number | Current count of active sessions |
root/terminalsChanged
Fired when the list of known terminals changes.
Full-replacement semantics: the terminals array replaces the previous terminals entirely.
| Field | Type | Description |
|---|---|---|
type | ActionType.RootTerminalsChanged | |
terminals | TerminalInfo[] | Updated terminal list (full replacement) |
root/configChanged
Fired when agent-host configuration values change.
By default, the reducer merges the new values into state.config.values. Set replace to true to replace all values instead of merging.
| Field | Type | Required | Description |
|---|---|---|---|
type | ActionType.RootConfigChanged | Yes | |
config | Record<string, unknown> | Yes | Updated config values |
replace | boolean | No | When true, replaces all config values instead of merging |
Commands
JSON Schema: commands.schema.json
listSessions
Returns a list of session summaries. Used to populate session lists and sidebars.
The session list is not part of the state tree because it can be arbitrarily large. Clients fetch it imperatively and maintain a local cache updated by root/sessionAdded and root/sessionRemoved notifications.
A large catalogue can be fetched incrementally via the {@link PaginatedParams} limit/cursor inputs (see that type for the full pagination contract). The server SHOULD return most-recently-modified entries first, so the first page is the immediately useful one. The root/session* notifications keep an already-fetched page live; pagination governs only the initial and backfill fetches.
| Property | Value |
|---|---|
| Direction | Client → Server |
| Type | Request |
Parameters:
| Field | Type | Description |
|---|---|---|
channel | 'ahp-root://' |
Result:
| Field | Type | Description |
|---|---|---|
items | SessionSummary[] | The list of session summaries. The server SHOULD order them most-recently-modified first. |
Example:
// Client → Server (fetch the first page of up to 50 sessions)
{ "jsonrpc": "2.0", "id": 4, "method": "listSessions",
"params": { "channel": "ahp-root://", "limit": 50 } }
// Server → Client (a cursor signals more entries exist)
{ "jsonrpc": "2.0", "id": 4, "result": {
"items": [ { "id": "s1", ... }, { "id": "s2", ... } ],
"nextCursor": "eyJvIjo1MH0="
}}
// Client → Server (fetch the next page)
{ "jsonrpc": "2.0", "id": 5, "method": "listSessions",
"params": { "channel": "ahp-root://", "limit": 50, "cursor": "eyJvIjo1MH0=" } }resolveSessionConfig
Iteratively resolves the session configuration schema. The client sends the current partial session config and any user-filled metadata values. The server returns a property schema describing what additional metadata is needed, contextual to the current selections.
The client calls this command whenever the user changes a significant input (e.g. picks a working directory, toggles a property). Each response returns the full current property set (not a delta). The returned values contain server-resolved defaults to pass to createSession.
| Property | Value |
|---|---|
| Direction | Client → Server |
| Type | Request |
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
channel | 'ahp-root://' | Yes | |
provider | string | No | Agent provider ID |
workingDirectory | URI | No | Working directory for the session |
config | Record<string, unknown> | No | Current user-filled configuration values |
Result:
| Field | Type | Description |
|---|---|---|
schema | SessionConfigSchema | JSON Schema describing available configuration properties given the current context |
values | Record<string, unknown> | Current configuration values (echoed back with server-resolved defaults applied) |
Example:
// Step 1: Client picks a working directory
// Client → Server
{ "jsonrpc": "2.0", "id": 5, "method": "resolveSessionConfig",
"params": { "workingDirectory": "file:///home/user/my-project" } }
// Server → Client (git repo detected, offers worktree option)
{ "jsonrpc": "2.0", "id": 5, "result": {
"schema": {
"type": "object",
"properties": {
"target": { "type": "string", "title": "Target", "enum": ["workspace", "worktree"] }
}
},
"values": {}
}}
// Step 2: User enables worktree
// Client → Server
{ "jsonrpc": "2.0", "id": 6, "method": "resolveSessionConfig",
"params": { "workingDirectory": "file:///home/user/my-project",
"config": { "target": "worktree" } } }
// Server → Client (now requires branch selection)
{ "jsonrpc": "2.0", "id": 6, "result": {
"schema": {
"type": "object",
"properties": {
"target": { "type": "string", "title": "Target", "enum": ["workspace", "worktree"] },
"baseBranch": { "type": "string", "title": "Base Branch",
"enum": ["main", "develop"],
"enumLabels": ["main", "develop"] }
},
"required": ["baseBranch"]
},
"values": { "target": "worktree" }
}}sessionConfigCompletions
Queries the server for allowed values of a dynamic session config property.
Used when a property in the schema returned by resolveSessionConfig has enumDynamic: true. The client sends a search query and receives matching values with display metadata.
| Property | Value |
|---|---|
| Direction | Client → Server |
| Type | Request |
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
channel | 'ahp-root://' | Yes | |
provider | string | No | Agent provider ID |
workingDirectory | URI | No | Working directory for the session |
config | Record<string, unknown> | No | Current user-filled configuration values (provides context for the query) |
property | string | Yes | Property id from the schema to query values for |
query | string | No | Search filter text (empty or omitted returns default/recent values) |
Result:
| Field | Type | Description |
|---|---|---|
items | SessionConfigValueItem[] | Matching value items |
Example:
// Client → Server (user types "ma" in branch picker)
{ "jsonrpc": "2.0", "id": 7, "method": "sessionConfigCompletions",
"params": { "workingDirectory": "file:///home/user/my-project",
"config": { "target": "worktree" },
"property": "baseBranch", "query": "ma" } }
// Server → Client
{ "jsonrpc": "2.0", "id": 7, "result": {
"items": [
{ "value": "main", "label": "main", "icon": "git-branch" },
{ "value": "main-v2", "label": "main-v2", "icon": "git-branch" }
]
}}Notifications
JSON Schema: notifications.schema.json
root/sessionAdded
Broadcast to all clients subscribed to the root channel when a new session is created.
| Property | Value |
|---|---|
| Direction | Server → Client |
| Type | Notification |
Parameters:
| Field | Type | Description |
|---|---|---|
channel | URI | Channel URI this notification belongs to (the root channel) |
summary | SessionSummary | Summary of the new session |
Example:
{
"jsonrpc": "2.0",
"method": "root/sessionAdded",
"params": {
"channel": "ahp-root://",
"summary": {
"resource": "ahp-session:/<uuid>",
"provider": "copilot",
"title": "New Session",
"status": 1,
"createdAt": "2024-03-09T16:00:00.000Z",
"modifiedAt": "2024-03-09T16:00:00.000Z"
}
}
}root/sessionRemoved
Broadcast to all clients subscribed to the root channel when a session is disposed.
| Property | Value |
|---|---|
| Direction | Server → Client |
| Type | Notification |
Parameters:
| Field | Type | Description |
|---|---|---|
channel | URI | Channel URI this notification belongs to (the root channel) |
session | URI | URI of the removed session |
Example:
{
"jsonrpc": "2.0",
"method": "root/sessionRemoved",
"params": {
"channel": "ahp-root://",
"session": "ahp-session:/<uuid>"
}
}root/sessionSummaryChanged
Broadcast to all clients subscribed to the root channel when an existing session's summary changes (title, status, modifiedAt, model, working directory, read/done state, or diff statistics).
This notification lets clients that maintain a cached session list — for example, the result of a previous listSessions() call — stay in sync with in-flight sessions without having to subscribe to every session URI individually. It is complementary to, not a replacement for, root/sessionAdded and root/sessionRemoved: those signal lifecycle (creation/disposal), while this signals summary-level mutations on an already-known session.
Semantics:
- Only fields present in
changeshave new values; omitted fields are unchanged on the client's cached summary. - Identity fields (
resource,provider,createdAt) never change and are not carried. - Like all protocol notifications, this is ephemeral: it is not replayed on reconnect. On reconnect, clients should re-fetch the full catalog via
listSessions()as usual. - The server SHOULD emit this notification whenever any mutable field on {@link SessionSummary |
SessionSummary} changes for a session the server has surfaced vialistSessions()orroot/sessionAdded. Servers MAY coalesce or debounce updates for noisy fields (for example,modifiedAtbumps while a turn is streaming) at their discretion. - Clients that have no cached entry for
sessionMAY ignore the notification; it is not a substitute forroot/sessionAdded.
| Property | Value |
|---|---|
| Direction | Server → Client |
| Type | Notification |
Parameters:
| Field | Type | Description |
|---|---|---|
channel | URI | Channel URI this notification belongs to (the root channel) |
session | URI | URI of the session whose summary changed |
changes | Partial<SessionSummary> | Mutable summary fields that changed; omitted fields are unchanged. Identity fields ( resource, provider, createdAt) never change and MUST be omitted by senders; receivers SHOULD ignore them if present. |
Example:
{
"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"
}
}
}root/progress
Generic progress notification for a long-running operation.
A client opts in to progress for a request by including a progressToken in that request (today: the progressToken field on createSession). If the server does long-running work to service the request — e.g. lazily downloading an agent's native SDK the first time a session of that provider is materialized — it emits progress notifications carrying the same token.
The notification is operation-agnostic: it says nothing about what is progressing. The client correlates progressToken back to the request it originated from (and thus the UI surface awaiting it) and renders its own localized indicator. The same channel serves any future long-running operation without a new method.
Semantics:
progressis monotonically non-decreasing for a givenprogressToken.totalis present only when the server knows the magnitude up front (e.g. aContent-Length); when absent the client SHOULD show an indeterminate indicator.- The operation is complete when
progress === total. The server MUST emit a final frame satisfyingprogress === total; when the total was never known, it setstotalto the finalprogresson that frame. No further frames reference the token afterwards. - The server MAY emit no progress at all (e.g. the work was already done); the client then never shows an indicator.
- Like all notifications this is ephemeral and is not replayed on reconnect. A client that never receives the terminal frame SHOULD expire the indicator after an idle timeout.
| Property | Value |
|---|---|
| Direction | Server → Client |
| Type | Notification |
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
channel | URI | Yes | Channel URI this notification belongs to (the root channel). |
progressToken | string | Yes | Echoes the progressToken the client supplied on the originating request (e.g. the progressToken field of createSession), correlating this frame to that call. Unique across the client's active requests. |
progress | number | Yes | Progress so far, in operation-defined units (e.g. bytes received). Monotonically non-decreasing for a given progressToken. |
total | number | No | Total when known up front (e.g. from a Content-Length); omitted ⇒ indeterminate. The operation is complete once progress === total. |
message | string | No | Optional human-readable progress message. The client owns its own (localized) presentation derived from the originating request; generic clients that don't track the token MAY display this instead. |
Example:
{
"jsonrpc": "2.0",
"method": "root/progress",
"params": {
"channel": "ahp-root://",
"progressToken": "9b2c1f7e-4a0d-4e2b-8b1a-2f7e4a0d4e2b",
"progress": 18874368,
"total": 41957498
}
}