How It Works
CMDOP uses outbound-only gRPC connections from agents to a central Control Plane. Agents authenticate via OAuth, register their capabilities, and maintain bidirectional streams. Sessions persist independently of client connections with a grace period for reconnection. The Control Plane routes messages between agents and multiple attached clients in real time.
This page explains the connection flow, session lifecycle, and message routing in CMDOP.
How does the connection flow work?
How does an agent start up?
When an agent starts on a target machine:
How does a client attach to a session?
When a client wants to interact with a session:
How is a command executed?
When a client sends a command:
What is the session lifecycle?
What states can a session be in?
What does each session state mean?
| State | Description | Timeout |
|---|---|---|
| PENDING | Session created, waiting for connection | β |
| CONNECTED | Active bidirectional streaming | Heartbeat: 60s |
| BACKGROUND | Mobile app backgrounded | 1 hour |
| GRACE_PERIOD | Agent disconnected, waiting for reconnect | 30 seconds |
| DISCONNECTED | Final state, session ended | β |
How does the grace period work?
The grace period is a key innovation. When an agent disconnects:
- Session enters GRACE_PERIOD state (not immediately DISCONNECTED)
- Processes continue running on the machine
- Output is buffered
- Agent has 30 seconds to reconnect
- If reconnected β seamless continuation
- If timeout β session moves to DISCONNECTED
# Example: Laptop closes, process continues
# Execute a command on the remote machine via the SDK
await client.terminal.execute("long_running_script.sh")
# Close laptop lid β agent enters GRACE_PERIOD state (30s window)
# ... 10 seconds later ...
# Open laptop β agent reconnects within grace period
# Script still running, buffered output is delivered to clientHow do heartbeats and health checks work?
What does the agent heartbeat contain?
Agents send heartbeats every 30 seconds:
# Heartbeat payload sent from agent to Control Plane every 30 seconds
HeartbeatUpdate:
session_id: "abc-123" # Identifies which session this heartbeat belongs to
timestamp: "2024-01-15T10:30:00Z"
system_metrics: # Real-time telemetry from the target machine
cpu_percent: 45.2
memory_percent: 62.1
disk_percent: 78.5
battery_percent: 85 # Mobile only β included for iOS agentsHow does connection keepalive work?
gRPC streams send ping frames every 25 seconds to prevent NAT timeout (typically 30-60 seconds).
What health checks are performed?
| Check | Interval | Action on Failure |
|---|---|---|
| Agent heartbeat | 60s | Mark session GRACE_PERIOD |
| gRPC keepalive | 25s | Reconnect attempt |
| Client heartbeat | 30s | Close stream |
How does multi-client attachment work?
Multiple clients can attach to the same session:
What access modes are available?
| Mode | Can Send Input | Receives Output |
|---|---|---|
| OPERATOR | β | β |
| OBSERVER | β | β |
How is input from multiple operators arbitrated?
When multiple operators send input:
- Commands queued in order received
- Each command gets unique command_id
- Output tagged with command_id for correlation
How do file operations work?
File operations go through the same session:
How are large files transferred?
For files over chunk threshold:
- Agent reads file in chunks (64KB-2MB adaptive)
- Each chunk sent as separate message
- MD5 checksum calculated incrementally
- Client reassembles and verifies