Skip to Content

Machines & Identity

Every Connect operation — interactive attach, one-shot exec, share-link creation, agent-to-agent calls, remote filesystem reads — funnels through a single resolver that turns the string you type into a concrete machine in the active workspace. This page describes what that resolver knows about a machine and how it picks one.

The four identifiers

A machine carries four kinds of names. They are not interchangeable:

FieldSourceStable?
IDserver-assigned UUIDYes — survives renames, OS reinstalls, reboots.
Hostnameos.Hostname() on the agent hostNo — changes if the OS hostname changes; may include .local on macOS.
Namefriendly label (defaults to Hostname)Editable in the desktop app and dashboard.
Prefixfirst unique characters of Hostname or NameConvenience only — not a real identifier.

The MachineInfo struct lives in internal/connect/machines/types.go:14–60 and is what every Connect tool sees:

type MachineInfo struct { ID string // UUID, stable Hostname string // OS-reported Name string // friendly label Online bool // cached, may lag HeartbeatAgeSeconds int64 // freshness signal — preferred over Online WorkspaceID string WorkspaceName string AgentVersion string ActiveSession *ActiveTerminalSession }

Resolution priority

machines.Resolve() (in internal/connect/machines/filter.go) tries the input string against the machine list in this order, stopping at the first match:

  1. UUID short-circuit. If the input matches the canonical 8-4-4-4-12 UUID shape (case-insensitive), it is matched against MachineInfo.ID. No fall-through — if no UUID matches, you get an error, not a fuzzy guess.
  2. Exact hostname. Equal to Hostname after lowercasing.
  3. Exact display name. Equal to Name after lowercasing. Useful when the friendly label diverges from the OS hostname.
  4. Unique fuzzy prefix. A substring or prefix match across both Hostname and Name. If exactly one machine matches, it wins.
  5. Ambiguous. Two or more candidates → error with a candidate list.
  6. No match. Error with the input echoed.

All consumers — cmdop connect, cmdop connect exec, ask_agent, ask_agents, remotefs.Open — funnel through one machines.Resolve(). You only need to learn the precedence once.

Online flag vs heartbeat age

MachineInfo.Online is a cached boolean populated by the relay. It reflects what the dashboard saw at the last list refresh, which can lag real state by seconds to minutes. For freshness-sensitive logic the authoritative signal is HeartbeatAgeSeconds:

  • 0–30s — recent heartbeat, machine is live.
  • 30–90s — possibly degraded; the daemon may be running but its relay link is flaky.
  • >90s — server will mark the machine offline on the next sweep.

The agent tool surface uses Online as the gate (online_only=true is the default for ask_agents, false for connect.list per tool.go:34), but when you need to debug a flaky machine, HeartbeatAgeSeconds is the number to look at.

The whoami operation

The connect agent tool exposes operation=whoami, which is the simplest way to ask “where am I?” from inside an agent prompt:

{ "operation": "whoami" }

The implementation calls os.Hostname() and matches against the workspace list (case-insensitive). The result is one of:

{ "matched": true, "hostname": "mac-studio", "machine_id": "8f23..." } { "matched": false, "hostname": "mac-studio", "reason": "not in workspace" } { "matched": false, "hostname": "mac-studio", "reason": "api unreachable" }

If the API is unreachable, whoami degrades gracefully: it still returns the local hostname so prompts can use it as context. See internal/connect/CLAUDE.md §whoami.

Listing machines

The CLI surfaces three views of the machine list:

# All machines in the active workspace. cmdop connect --list # Only the ones currently online. cmdop connect --list --online # JSON for scripting. cmdop connect --list --json

A typical row in the human-readable output looks like:

NAME HOSTNAME ID ONLINE AGE SESSION mac-studio mac-studio.local 8f23... yes 4s — prod-api-1 prod-api-1 a142... yes 12s active (jane@bmw) vps-audi vps-audi c9f8... no 4m12s — vps-bmw vps-bmw f200... yes 3s —

The SESSION column is populated from MachineInfo.ActiveSession. It shows whether somebody else is currently attached.

Fuzzy matching pitfalls

Two patterns cause confusion:

  1. Ambiguous prefixes. If you type prod and the workspace contains prod-api-1, prod-api-2, prod-db-1, the resolver returns:

    ambiguous machine "prod" — matches: prod-api-1, prod-api-2, prod-db-1

    The fix is to type more characters until exactly one machine matches, or to use the UUID prefix instead.

  2. macOS .local suffix. On macOS, os.Hostname() often returns mac-studio.local. The resolver matches this permissively — both mac-studio and mac-studio.local resolve to the same machine.

A single-character prefix is rejected outright to avoid surprises. Use at least two characters when matching by prefix.

Renaming a machine

The OS hostname and the friendly name can both change. MachineInfo.ID cannot. Rename flow:

  • Edit the friendly name from the desktop app’s machines tab or the dashboard.
  • Or change the OS hostname; the agent re-registers under the new value on its next heartbeat.

For the duration of the legacy reconciliation window (server-side), the old hostname continues to resolve. Long-running scripts should switch to UUID before assuming the rename has propagated everywhere.

For unattended scripts (CI, scheduled jobs, fan-out automations), prefer the UUID. It is immune to renames and never ambiguous. Save hostnames and prefixes for interactive flows where a human is reading the output.

Active session info

When somebody is attached to a machine, MachineInfo.ActiveSession carries enough information for the dashboard and TUI picker to show “already in use” hints:

type ActiveTerminalSession struct { SessionID string StartedAt time.Time Operator string // hostname of the client that opened the session }

This is purely informational — multiple clients can attach to the same session. The desktop app uses it to dim machines that already have an operator. See interactive-attach for the multi-client model.

Cross-workspace addressing

A machine belongs to exactly one workspace. To talk to a machine in a different workspace, switch first:

cmdop connect workspace use staging cmdop connect exec vps-bmw -- uptime

There is no syntax for “machine X in workspace Y” in a single call — that is by design, because the relay enforces workspace scoping at the auth layer.

Where machines are scoped, and how to switch between them.

The picker UI uses the same resolver under the hood.

Common entry point that surfaces resolver errors directly.

ask_agent and ask_agents use the same fuzzy matcher.

Last updated on