Agents
A CMDOP agent is a lightweight Go binary on each machine that registers via OAuth or a workspace API key and exposes a typed agent loop over the relay — the per-machine node of the execution-state continuity layer. It bundles a daemon process (holds the outbound-only TLS connection, serves local clients) and an LLM-driven loop (plans turns, calls tools). Every connection is outbound, so no inbound ports, port forwarding, or firewall changes are needed.
A CMDOP agent is a lightweight Go binary that runs on each machine, registers via OAuth or a workspace API key, and exposes a typed agent loop over the relay. This page is the high-level mental model — for the turn cycle see Agent Loop, for the tool catalogue see Tools.
What is a CMDOP agent?
The agent is two things bundled together:
- A daemon process that holds the outbound TLS connection, serves local clients over a Unix socket / named pipe, and runs background work (heartbeats, triggers, updates). See Daemon.
- An LLM-driven loop that, when invoked, plans turns, calls tools, and produces answers. See Agent Loop.
The same Go core powers Desktop, CLI, and SDK. There is no “cloud agent” — your code runs where the daemon runs.
Outbound-only architecture
Every connection the agent makes is outbound. The relay never reaches into your network.
Traditional remote access:
CMDOP:
Engineering benefits:
- No inbound ports on target machines.
- Works through CGNAT (carrier-grade NAT, common on consumer ISPs).
- Works through corporate proxies that allow HTTPS but block inbound and SSH.
- No port forwarding or firewall configuration required.
Agent vs Daemon vs Session
These three terms get conflated. They are distinct:
| Term | What it is |
|---|---|
| Daemon | The long-running OS process. Holds the relay connection, serves local clients. |
| Agent | The LLM loop running inside the daemon (and inside Desktop / CLI / SDK). |
| Session | A single conversation or PTY attached to the agent. |
A daemon hosts many agent invocations. An agent invocation produces zero or more sessions.
The agent loop, in one paragraph
Each turn the runner injects fresh system context (identity, env, target machine), resolves
the tool catalogue, sanitises history, and calls the LLM. If the model emits tool calls,
the runner executes them (concurrently when allowed) and appends results. The loop
terminates when the model returns text without tool calls, when maxTurns is hit, or when
the user cancels. Temperature is fixed at 0.3, retries are 6× exp backoff (500 ms → 32 s).
Source: internal/agent/runner/loop.go:61–300.
For the full cycle and pseudocode see Agent Loop.
Builtin tools
The agent ships with a curated tool catalogue (system, file, logs, remote, board, meta). Every tool has a JSONSchema and a Go handler. Highlights:
- System —
execute_command,write_file,download_file. - FileRead —
read_file,grep,glob,list_dir. - Logs —
read_logs(tails the daemon log). - Remote —
connect,connect_session,ask_machine,ask_machine_stream,ask_machines. - Board / Meta — issue CRUD, todo list, skill runner, delegate.
Full reference in Tools and the per-category guides.
Identity and registration
Every machine has a stable server-issued UUID, a hostname (OS-reported), and an optional friendly name. Each agent also carries its own Ed25519 keypair — a cryptographic identity it owns, independent of any cloud account. Agents register under their fleet’s credentials (API key or OAuth) and heartbeat to keep the machine flagged ONLINE. See Machine Identity and Identity & the private contour.
Where the agent runs
The exact same Go core is embedded everywhere:
| Surface | Façade | Notes |
|---|---|---|
| Desktop chat tab | chat.ForDesktop | Runs in the Wails-bundled daemon. |
| CLI | chat.ForCLI | Thin wrapper, uses the local daemon. |
Daemon (inbound ask_machine) | chat.ForDaemon | Receives remote calls; gated by permissions.yaml. |
| SDK | chat.ForSDK | Programmatic access, same loop. |
| TUI | chat.ForTUI | Terminal UI surface. |
See internal/chat/CLAUDE.md for the façade table and report 04 §13.
Limits and the safety net
The agent is not sandboxed — it inherits the OS user that runs the daemon. CMDOP layers several checks on top:
- Floor checks (
internal/agent/safety/): non-bypassable patterns (rm -rf /, fork bombs, writes to.env,.git,~/.ssh,/etc, …). - Permission gate: every tool call from a remote agent is filtered by
permissions.yaml. See Permissions. - Linux seccomp blacklist: process-level filter on supported kernels.
Local chat is unsupervised
The agent runs locally on each machine. CMDOP never executes your code in the cloud.
Local chat (cmdop chat, TUI, SDK on the same OAuth identity) bypasses the permission
gate. The gate fires only for remote agents calling this agent. See
Permissions.
Starting and checking an agent
# start the daemon (foreground; use --service for background)
cmdop agent start
# check status
cmdop agent status
# → ONLINE
# pid: 48211
# workspace: ws_acme_prod
# relay: connected
# last heartbeat: 2s agoSee Daemon for boot steps, status semantics, and log locations.
Related
TAGS: agents, outbound-only, daemon, agent-loop, identity DEPENDS_ON: [daemon, agent-loop, tools, permissions]