Sessions
A CMDOP session is a unit of the execution-state continuity layer: a single-homed, stored, resumable object that lives in the database rather than on a connection, so it survives client disconnects and re-attaches from any device. Two flavours exist — terminal sessions (one PTY, 30 s grace) and persistent sessionmgr sessions (many commands, 1 MiB ring buffer, 30 min idle TTL). The relay routes by ID, not IP.
A CMDOP session is a stored, resumable object. It is not tied to a network connection — it lives in the database, survives client disconnects, and can be re-attached from any device. There are two flavours, and they are easy to confuse.
Sessions are objects, not connections
Where SSH binds a session lifetime to one TCP socket, CMDOP decouples them. The session is a database row plus runtime state on the agent; clients (Desktop, CLI, mobile, SDK) attach and detach over the relay. Multiple clients can attach to the same session concurrently — see Multi-Client.
Traditional SSH:
Connection ═══════ Session
└─ connection closes → session dies
CMDOP:
Connection ────┐
Connection ────┼──▶ Session (persistent object)
Connection ────┘
└─ connections come and go, session persistsTwo kinds of sessions
| Kind | Surface | Lifetime | Identity | Idle behaviour |
|---|---|---|---|---|
| Terminal session | cmdop connect, Desktop machines tab | One PTY, one client at a time as operator | Server UUID issued on open | 30 s grace on disconnect, then closes |
| Persistent (sessionmgr) | connect_session agent tool, board task runners | Many commands within one channel | host-uuid:slotN (daemon-issued) or machine_<uuid>_<hex> (Desktop machine-scoped) | 30 min idle TTL by default; per-session override |
Same word, different objects. Use Remote Sessions for the persistent flavour.
Lifecycle states
The persistent session walks a small state machine:
Source of truth: internal/connect/sessionmgr/types.go:18–78.
Terminal sessions have a similar but simpler shape — see the grace-period section below.
Identity
Two ID formats appear in logs and APIs:
host-uuid:slotN— daemon-issued for sessionmgr sessions (e.g.prod-1:slot3).machine_<uuid>_<hex>— minted by the Desktop frontend when a chat is machine-scoped, then decoded by the chat service (TargetMachineIDflows throughchat.Optional). See report 05 §2.8 and the per-machine chat path.
Both are addressable from any client; the relay routes by ID, not by IP.
The ring buffer (sessionmgr only)
Persistent sessions buffer output in a per-session ring (default 1 MiB). The contract:
Write(b)— appends, drops oldest on overflow, setstruncated=true.Since(offset) → (data, nextCursor, truncated)— returns bytes sinceoffset. Atruncated=trueanswer signals that the requested offset fell outside the current window and bytes were lost.
Source: internal/connect/sessionmgr/ringbuf.go:14–84. See Remote Sessions
for the read pattern.
Idle behaviour and the reaper
The sessionmgr runs a reaper goroutine that closes sessions idle longer than the TTL
(30 min by default). Per-session override via IdleTTL on Open:
IdleTTL=0— disable auto-close (use for builds, deploys, log tails).- Small value — quick health probes that should free up slots fast.
If a session is idle 30+ minutes, the manager closes it. To keep a long task alive, set
IdleTTL=0 on open.
Grace period (terminal sessions)
When a terminal session’s client disconnects (laptop closes, network blip), the agent does not tear the PTY down immediately. The session enters a 30-second grace window:
- Process keeps running on the agent host.
- Output is buffered for replay.
- If the client (or any other fleet member) reconnects within 30 s, the stream resumes seamlessly.
- If 30 s elapses with no reconnect, the session closes.
This means flaky networks don’t kill long commands. A reconnect from a different device (phone, another laptop) attaches to the same session.
Where each kind is used
| Kind | Typical use |
|---|---|
| Terminal session | cmdop connect, Desktop machines tab interactive shell |
| Persistent (sessionmgr) | connect_session agent tool; board task runners that must issue many commands |
Cross-link: Remote Sessions for the sessionmgr surface; Multi-Client for the operator/observer model on terminal sessions.
Reconnecting from another device
# laptop, opens a session
cmdop connect prod-1
# (laptop closes, session continues)
# phone or another machine — list active sessions in fleet
cmdop session list
# inspect a session's metadata by ID
cmdop session attach <session-id>
# reattach interactively to the live terminal
cmdop connect prod-1Reconnect from any device — sessions are not bound to the originating client. Interactive reattach (a live terminal) is done with cmdop connect; cmdop session attach currently reports the session’s metadata and marks it attached, with interactive takeover planned but not yet implemented.
sessionmgr open with IdleTTL=0
{
"tool": "connect_session",
"args": {
"hostname": "prod-1",
"operation": "open",
"idle_ttl_ms": 0
}
}IdleTTL=0 disables the reaper for that session — the agent must close it explicitly.
Limits
- One operator per terminal session at a time (others attach as observers).
- 64 sessionmgr sessions per daemon process (default).
- 1 MiB ring buffer per persistent session.
- 30 s terminal grace, 30 min sessionmgr idle TTL — both overridable.
Related
Background reading: The Session as a Computational Primitive — the category essay on why the session, not the connection, is the durable object.
TAGS: sessions, sessionmgr, ring-buffer, idle-ttl, grace-period DEPENDS_ON: [agents, remote-sessions, multi-client]