Skip to content

Protocol Reference

This page documents the IPC protocol that clients use to communicate with the carryOn daemon. It is intended for contributors building new clients or integrations, not for day-to-day use of carryOn.

The daemon listens on a Unix domain socket. Clients connect to the socket to send commands and receive events.

PlatformPath
macOS / Linux~/.carryon/daemon.sock
WindowsNamed pipe: \\.\pipe\carryon-daemon

All communication happens over a single bidirectional connection using a binary framing protocol with JSON-RPC messages inside.

Every message on the wire is wrapped in a binary frame:

[type:1][sessionIdLen:4][sessionId:N][payloadLen:4][payload:N]
FieldSizeDescription
type1 byteFrame type identifier (see table below)
sessionIdLen4 bytesLength of the session ID string (big-endian uint32)
sessionIdN bytesSession ID as a UTF-8 string. May be empty (length 0) for frames not associated with a session.
payloadLen4 bytesLength of the payload (big-endian uint32)
payloadN bytesFrame-type-specific data
NameType byteDirectionPayload
TerminalData0x01BothRaw terminal I/O bytes. Client-to-daemon carries user input; daemon-to-client carries terminal output.
Resize0x02Client-to-daemonTerminal dimensions as JSON: {"cols": 80, "rows": 24}
StreamClose0x03Daemon-to-clientSignals that the stream for a session has ended. No payload.
JsonRpc0xFFBothA JSON-RPC 2.0 request, response, or notification (UTF-8 encoded).

TerminalData frames carry the session ID of the target session. JsonRpc frames may have an empty session ID when the request is not session-specific.

All RPC communication uses JSON-RPC 2.0 encoded inside JsonRpc frames. Methods are grouped by category below.

MethodParamsDescription
client.identify{ clientType, clientName }Identify the connecting client. Should be sent immediately after connecting.
MethodParamsDescription
session.create{ name?, backend? }Create a new session. Returns the session ID and name.
session.listnoneList all active sessions with their metadata.
session.attach{ sessionId }Attach to a session and begin receiving its output.
session.detach{ sessionId }Detach from a session.
session.kill{ sessionId }Terminate a session and its processes.
session.rename{ sessionId, newName }Rename a session.
MethodParamsDescription
daemon.statusnoneReturn unified status including daemon, local server, remote access, and backends.
daemon.stopnoneRequest a graceful daemon shutdown.
MethodParamsDescription
config.get{ key }Read a config value.
config.set{ key, value }Write a config value.
config.reloadnoneReload configuration from disk.
config.pathnoneReturn the path to the config file.

Some config keys trigger immediate side effects when set:

KeySide effect
local.enabledStarts or stops the local HTTP server
local.portRestarts the local server if running
local.exposeRestarts the local server if running
remote.enabledConnects or disconnects remote access
MethodParamsDescription
project.init{ path }Create a .carryon.json file at the given path.
project.terminals{ path }Start the terminals defined in the project config at the given path.
project.associate{ path }Associate a directory with its project sessions.
project.disassociate{ path }Remove the project association for a directory.

The daemon sends unsolicited JSON-RPC notifications to connected clients when state changes. These use the standard JSON-RPC notification format (no id field).

NotificationDataDescription
session.created{ sessionId, name, backend }A new session was created.
session.closed{ sessionId }A session was terminated.
session.renamed{ sessionId, oldName, newName }A session was renamed.
client.attached{ sessionId, clientType, clientName }A client attached to a session.
client.detached{ sessionId, clientType, clientName }A client detached from a session.
local.statusChanged{ enabled }The web UI was started or stopped.

Each session backend uses a “holder” process that owns the actual terminal. The holder protocol defines how the daemon communicates with these processes to manage the terminal lifecycle, relay I/O, and handle resizing.

The full holder protocol specification is available in the CLI repository at docs/PROTOCOL.md.