Terminal Channel
Reference for the ahp-terminal:/<id> channel — long-lived pseudo-terminals that can be attached to clients and/or sessions. See Terminal Channel specification for the wire-level overview.
JSON Schema: state.schema.json
State Types
TerminalInfo
Lightweight terminal metadata exposed on the root state.
| Field | Type | Required | Description |
|---|---|---|---|
resource | URI | Yes | Terminal URI (subscribable for full terminal state) |
title | string | Yes | Human-readable terminal title |
claim | TerminalClaim | Yes | Who currently holds this terminal |
exitCode | number | No | Process exit code, if the terminal process has exited |
TerminalClaimKind
Discriminant for terminal claim kinds.
| Member | Value |
|---|---|
Client | 'client' |
Session | 'session' |
TerminalClientClaim
A terminal claimed by a connected client.
| Field | Type | Description |
|---|---|---|
kind | TerminalClaimKind.Client | Discriminant |
clientId | string | The clientId of the claiming client |
TerminalSessionClaim
A terminal claimed by a session, optionally scoped to a specific turn or tool call.
| Field | Type | Required | Description |
|---|---|---|---|
kind | TerminalClaimKind.Session | Yes | Discriminant |
session | URI | Yes | Session URI that claimed the terminal |
turnId | string | No | Optional turn identifier within the session |
toolCallId | string | No | Optional tool call identifier within the turn |
TerminalClaim
Describes who currently holds a terminal. A terminal may be claimed by either a connected client or a session (e.g. during a tool call).
TerminalClientClaim | TerminalSessionClaim
TerminalState
Full state for a single terminal, loaded when a client subscribes to the terminal's URI.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Human-readable terminal title |
cwd | URI | No | Current working directory of the terminal process |
cols | number | No | Terminal width in columns |
rows | number | No | Terminal height in rows |
content | TerminalContentPart[] | Yes | Typed content parts, replacing the flat content: string.Naive consumers that only need the raw VT stream can reconstruct it with: content.map(p => p.type === 'command' ? p.output : p.value).join('')Consumers that need command boundaries can filter by part type. |
exitCode | number | No | Process exit code, set when the terminal process exits |
claim | TerminalClaim | Yes | Who currently holds this terminal |
supportsCommandDetection | boolean | No | Whether this terminal emits terminal/commandExecuted and terminal/commandFinished actions and populates command-typed parts.Clients MUST check this flag before relying on command detection. Do NOT use the presence of a command part as a feature flag — parts are absent in the normal idle state. |
TerminalContentPart
A content part within terminal output.
TerminalUnclassifiedPart | TerminalCommandPart
TerminalUnclassifiedPart
Unstructured terminal output — content before, between, or after commands, or from terminals that do not support command detection.
| Field | Type | Description |
|---|---|---|
type | 'unclassified' | Discriminant |
value | string | Accumulated VT output. Appended to by terminal/data when no command is executing. |
TerminalCommandPart
A single command: its command line and the output it produced.
While isComplete is false the command is still executing; output grows as terminal/data actions arrive. At terminal/commandFinished the part is mutated in-place with isComplete: true and the completion metadata.
| Field | Type | Required | Description |
|---|---|---|---|
type | 'command' | Yes | Discriminant |
commandId | string | Yes | Stable id matching the commandId on the corresponding terminal/commandExecuted and terminal/commandFinished actions. |
commandLine | string | Yes | The command line submitted to the shell. |
output | string | Yes | Accumulated VT output. Appended to by terminal/data while isComplete is false. Shell integration escape sequences are stripped by the server. |
timestamp | number | Yes | Unix timestamp (ms) when execution started, as reported by the server. |
isComplete | boolean | Yes | Whether the command has finished. |
exitCode | number | No | Shell exit code. Set at completion. undefined if unknown. |
durationMs | number | No | Wall-clock duration in milliseconds. Set at completion. |
Actions
Mutate TerminalState. Scoped to a terminal URI via the enclosing ActionEnvelope.channel.
JSON Schema: actions.schema.json
terminal/data
Terminal output data (pty → client direction).
Appends data to the terminal's content in the reducer.
terminal/data and terminal/input are intentionally separate actions because standard write-ahead reconciliation is not safe for terminal I/O. A pty is a stateful, mutable process — optimistically applying input or predicting output would produce incorrect state. Instead, terminal/input is a side-effect-only action (client → server → pty), and terminal/data is server-authoritative output (pty → server → client).
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalData | |
data | string | Output data (may contain ANSI escape sequences) |
terminal/input
Keyboard input sent to the terminal process (client → pty direction).
This is a side-effect-only action: the server forwards the data to the terminal's pty. The reducer treats this as a no-op since terminal/data actions will reflect any resulting output.
See terminal/data for why these two actions are kept separate.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalInput | |
data | string | Input data to send to the pty |
terminal/resized
Terminal dimensions changed.
Dispatchable by clients to request a resize, or by the server to inform clients of the actual terminal dimensions.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalResized | |
cols | number | Terminal width in columns |
rows | number | Terminal height in rows |
terminal/claimed
Terminal claim changed. A client or session transfers ownership of the terminal.
The server SHOULD reject if the dispatching client does not currently hold the claim.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalClaimed | |
claim | TerminalClaim | The new claim |
terminal/titleChanged
Terminal title changed.
Fired by the server when the terminal process updates its title (e.g. via escape sequences), or dispatched by a client to rename a terminal.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalTitleChanged | |
title | string | New terminal title |
terminal/cwdChanged
Terminal working directory changed.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalCwdChanged | |
cwd | URI | New working directory |
terminal/exited
Terminal process exited.
| Field | Type | Required | Description |
|---|---|---|---|
type | ActionType.TerminalExited | Yes | |
exitCode | number | No | Process exit code. undefined if the process was killed without an exit code. |
terminal/cleared
Terminal scrollback buffer cleared.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalCleared |
terminal/commandDetectionAvailable
Shell integration has loaded and the terminal now supports command detection. The server dispatches this when shell integration becomes available (which may happen asynchronously after the terminal is created).
Clients MUST NOT assume command detection is available until this action (or terminal/commandExecuted) has been received.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalCommandDetectionAvailable |
terminal/commandExecuted
A command has been submitted to the shell and is now executing. All subsequent terminal/data actions (until the matching terminal/commandFinished) constitute this command's output.
| Field | Type | Description |
|---|---|---|
type | ActionType.TerminalCommandExecuted | |
commandId | string | Stable identifier for this command, scoped to the terminal URI. Allows correlating commandExecuted → commandFinished pairs. |
commandLine | string | The command line text that was submitted |
timestamp | number | Unix timestamp (ms) of when the command started executing, as measured on the server. |
terminal/commandFinished
A command has finished executing.
The sequence of terminal/data actions between the preceding terminal/commandExecuted (same commandId) and this action constitutes the complete output of the command.
| Field | Type | Required | Description |
|---|---|---|---|
type | ActionType.TerminalCommandFinished | Yes | |
commandId | string | Yes | Matches the commandId from the corresponding commandExecuted |
exitCode | number | No | Shell exit code. undefined if the shell did not report one. |
durationMs | number | No | Wall-clock duration of the command in milliseconds, as measured by the shell integration script on the server side. |
Commands
JSON Schema: commands.schema.json
createTerminal
Creates a new terminal on the server.
After creation, the client should subscribe to the terminal URI to receive state updates. The server dispatches root/terminalsChanged to update the root terminal list.
| Property | Value |
|---|---|
| Direction | Client → Server |
| Type | Request |
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
channel | URI | Yes | Terminal URI (client-chosen). |
claim | TerminalClaim | Yes | Initial owner of the terminal |
name | string | No | Human-readable terminal name |
cwd | URI | No | Initial working directory URI |
cols | number | No | Initial terminal width in columns |
rows | number | No | Initial terminal height in rows |
Result: null on success.
disposeTerminal
Disposes a terminal and kills its process if still running.
The server dispatches root/terminalsChanged to remove the terminal from the root terminal list.
| Property | Value |
|---|---|
| Direction | Client → Server |
| Type | Request |
Parameters:
No parameters.
Result: null on success.