Skip to Content
DocsConceptsRemote sessions

Remote Sessions

TL;DR

A remote session is a single-homed execution-state object in the execution-state continuity layer: a persistent channel on a target machine that survives across many tool calls. Open once, then send and read repeatedly through a state machine (opening → ready → busy → closing → closed). A 1 MiB output buffer captures output so callers poll instead of stream, and an idle reaper closes quiet sessions after 30 minutes (override by disabling the idle TTL).

A remote session is a persistent shell-like channel on a target machine that survives across many tool calls. Where cmdop connect exec is one-shot, a persistent session is opened once, lets the agent issue many commands against it, and is torn down when idle. This page describes the contract.

What a persistent session gives you

  • Many commands, one channel. The agent can open once, then send and read repeatedly within a chat turn — and across turns.
  • Output buffering. A 1 MiB rolling output buffer per session captures stdout/stderr so the agent can poll instead of streaming.
  • State machine. Every session walks opening → ready → busy → closing → closed, so the agent can reason about what is happening without races.
  • Idle reaper. Sessions that go quiet for 30 minutes are closed automatically.

Lifecycle

Session-manager defaults:

  • Max sessions per process: 64.
  • Output buffer per session: 1 MiB.
  • Idle TTL: 30 minutes.

Public API

The agent-facing surface is the connect_session builtin tool with operations:

OperationPurpose
openReserve a slot; returns a session ID.
sendIssue a command on an existing session.
readPull buffered output since an offset.
closeTear the session down explicitly.
listEnumerate live sessions.

For the full tool catalogue see Tools.

The output buffer

Long-running commands easily print megabytes. The rolling output buffer caps memory at 1 MiB by dropping the oldest bytes when full. The contract:

  • New output is appended; once the window is full the oldest bytes are dropped and the buffer is flagged as truncated.
  • A reader asks for everything since a given offset and gets back the bytes, a cursor to resume from, and a truncated flag. A truncated answer means the requested offset fell outside the current window — the agent has missed bytes between this read and the previous one.

The agent uses truncated as a signal to back off and read in smaller windows, or to surface a warning to the user that some output was lost.

Idle TTL and the reaper

A background reaper closes sessions that have been idle for the manager’s TTL (30 min by default). The idle TTL can be overridden per session at open time:

Use caseIdle TTL
Quick interactive shellleave default (30 min)
Long build / deploy0 (no auto-close)
Tail a slow log0
Short-lived health probesmall (5–10 min)

An idle TTL of 0 disables the reaper for that session — close it explicitly when done.

Set the idle TTL to 0 for builds, deploys, or any task expected to take longer than 30 minutes.

Transport-agnostic

The session manager runs the same way against a real remote machine or an in-memory test double, so its behavior is identical in production and under test. Commands run either as a single request (for send) or over a bidirectional stream (for interactive operations).

Truncation handling pattern

When an agent reads since an offset and gets a truncated result, the recommended pattern is:

let offset = 0 loop { let (data, next, truncated) = read(session, offset) if truncated { warn("output truncated; consider increasing read frequency") } process(data) offset = next if done(data) { break } }

The agent exposes truncation in the chat as a warning so the user knows some bytes were dropped.

Example flow

// 1. open { "tool": "connect_session", "args": { "hostname": "prod-1", "operation": "open" } } // → { "session_id": "prod-1:slot3" } // 2. send { "tool": "connect_session", "args": { "session_id": "prod-1:slot3", "operation": "send", "command": "tail -F /var/log/nginx/access.log" }} // 3. read (poll) { "tool": "connect_session", "args": { "session_id": "prod-1:slot3", "operation": "read", "offset": 0 }} // → { "data": "...", "next_cursor": 4096, "truncated": false } // 4. close { "tool": "connect_session", "args": { "session_id": "prod-1:slot3", "operation": "close" }}

Limits and tuning

  • 64 live sessions per daemon process. Board automations that fan out heavily can hit this cap — coalesce or reuse sessions where possible.
  • 1 MiB buffer per session. Total output-buffer memory at the cap is ~64 MiB.
  • Per-session timeouts are independent of the manager’s idle TTL.

Persistent sessions reserve memory (1 MiB output buffer each). Default cap is 64 per process; tune for board automations that fan out heavily.