Daemon
The daemon is the long-running OS process started by cmdop agent start. Until it is up,
the machine is not online — every other CMDOP feature attaches to it.
Why the daemon is the on-ramp
The CLI, Desktop, and SDK never talk to the relay directly. They open a local gRPC channel
to the daemon over a per-user Unix socket (or Windows named pipe), and the daemon owns the
single outbound TLS connection to the relay. If the daemon is not running, cmdop chat
falls back to a one-shot mode and nothing else (machines tab, remote calls, share links)
works.
See internal/services/daemon/CLAUDE.md for the authoritative description, and
internal/services/localserver/ for the local socket server.
Startup sequence
cmdop agent start runs the following steps before the daemon is considered live (see
internal/services/daemon/agent_connection.go and report 06 §2.2):
- Initialise the file logger (lumberjack).
- Mark a new daemon session in the log file.
- Write the PID file at
~/.cmdop/cmdop.pid. - Bring up the status manager and write
daemon.status. - Install signal handlers (SIGINT / SIGTERM for graceful stop).
- Open the backlog store for offline tool-call queueing.
- Load the permissions store (rules + audit log).
- Start the OAuth token refresher.
- Schedule auto-update checks.
- Start the trigger scheduler (cron-style background jobs).
- Bring up the local gRPC server (Unix socket / named pipe).
- Optionally bring up the MCP server (
--with-mcp). - Enter the connection loop — dial the relay, register, heartbeat.
Only when step 13 completes a handshake does the daemon flip to ONLINE.
Status verdict — ONLINE / DEGRADED / STARTING
cmdop agent status reads daemon.status and the PID file, then returns one of three
verdicts:
| Verdict | Meaning |
|---|---|
| ONLINE | Process alive, status file fresh (< 30 s), relay handshake done. |
| DEGRADED | Process alive but status file stale (> 30 s) or relay disconnected. |
| STARTING | Process alive, never reached relay handshake (boot or recovery). |
// ~/.cmdop/daemon.status (excerpt)
{
"status": "ONLINE",
"pid": 48211,
"hostname": "laptop-a",
"workspace_id": "ws_acme_prod",
"relay_connected": true,
"last_heartbeat": "2026-04-27T14:55:12Z"
}ONLINE means the daemon is connected to the relay. If cmdop agent status reports
DEGRADED but the process is alive, the daemon failed to reach the relay — usually network,
auth, or token expiry. Run cmdop agent logs -f to see the cause.
Heartbeat and the online flag
The daemon calls statusManager.Touch() on every heartbeat tick. The relay holds a
server-side TTL of roughly 90 s — if heartbeats stop, the machine is marked offline on
that timeline. On a clean cmdop agent stop, the daemon also issues MarkOfflineByHostname
with a 3-second deadline so the UI flips immediately rather than waiting on the TTL.
PID file is per-user
~/.cmdop/cmdop.pid is per-euid, not host-wide. Two daemons can legitimately coexist —
typically a user daemon plus a root daemon on the same host, or two OAuth accounts on a
shared VM. findOtherAgentProcess() only prints a hint when something looks suspicious;
it never blocks startup.
cmdop agent stop marks the machine offline immediately via a 3-second RPC. If you
kill -9 the daemon, the relay keeps the machine listed as ONLINE for ~90 s until the
heartbeat TTL expires.
Workspace ID flow
The daemon reads its WorkspaceID from the auth manager once, during connection setup.
Switching workspaces is not an in-place mutation — it triggers a reconnect so the new
WorkspaceID flows through the metadata of every gRPC call.
Do not cache or hand-mutate workspace state. See Workspaces for the credential resolver and report 06 §2.7 for the precise sequence.
Logs and rotation
Logs go through lumberjack (size-based rotation). Since 2026-04-19 the daemon does not
rotate on every start; it appends, with a === DAEMON SESSION START === marker so you can
grep for boot boundaries. Tail with:
cmdop agent logs -fLocations are platform-specific (~/Library/Logs/cmdop/ on macOS,
~/.local/state/cmdop/ on Linux, %LOCALAPPDATA%\cmdop\Logs\ on Windows).
States as a diagram
MCP server (opt-in)
cmdop agent start --with-mcp exposes the agent’s tool surface to MCP clients (Claude
Desktop, Cursor, VSCode). Off by default. See MCP for the integration story.
Related
TAGS: daemon, lifecycle, status, heartbeat, online DEPENDS_ON: [agents, machine-identity, workspaces]