Skip to Content

Workspaces

A workspace is the tenant boundary for Connect. It owns the machines you can reach, the API key (or OAuth token) that lets you reach them, and the relay server those calls flow through. Most people start with one workspace; teams that work across companies, environments, or relay deployments end up with several.

What lives in a workspace

When Connect resolves a target, it does so inside the active workspace. That means a workspace owns:

  • Machines. Every registered host is scoped to exactly one workspace at a time. cmdop connect --list only shows machines in the current workspace.
  • API key. A single workspace-scoped credential, optionally overridden by --api-key per call.
  • Server (optional). A per-workspace gRPC override for on-prem relay deployments — most users leave this blank and use the default cloud relay.
  • Sync metadata. RemoteID, RemoteName, and LastSyncedAt are populated when you run cmdop connect workspace sync against an OAuth session.

The struct is defined in internal/connect/workspace/types.go:20–28.

API keys belong to one workspace. To talk to machines in workspace B you need a key for B (or you sign in with OAuth, which carries the active workspace in the token).

The local store

Workspaces live in ~/.cmdop/ssh_workspaces.json with mode 0600. The file is per-user, never synced over the network, and only writable by the daemon or the CLI under your euid. The schema is intentionally tiny:

{ "active": "production", "workspaces": [ { "name": "production", "api_key": "ck_live_***REDACTED***", "server": "", "remote_id": "ws_8f23...", "remote_name": "Acme Production", "last_synced_at": "2026-04-22T11:04:31Z" }, { "name": "staging", "api_key": "ck_test_***REDACTED***" } ] }

The filename still says ssh_workspaces.json for historical reasons — the package was renamed ssh → connect but the on-disk format kept the old name to avoid a breaking migration. It may be renamed in a future release; treat the path as an implementation detail.

workspace.DefaultStore() lazily loads this file on first access and keeps a process-wide singleton. See internal/connect/workspace/store.go.

Listing and switching

The CLI exposes the workspace lifecycle under cmdop connect workspace (short alias ws):

# What workspace am I in right now? cmdop connect workspace # All workspaces, with the active one marked. cmdop connect workspace list # Switch the active workspace. cmdop connect workspace use staging # Drop a local workspace (does not touch the server). cmdop connect workspace remove old-poc

When you run workspace use, the daemon notices the change at its next relay handshake and reconnects with the new WorkspaceID. Sessions opened under the previous workspace are not visible from the new one.

Switching the active workspace causes the daemon to drop and re-establish its relay connection. Any in-flight cmdop connect attach or ssh_session session against the previous workspace will end.

Sync from the server

If you signed in with cmdop login, the OAuth token can pull the authoritative workspace list from the dashboard:

cmdop login # one-time cmdop connect workspace sync

sync calls /apix/machines/workspaces/, upserts every workspace it sees (matching by RemoteID, then by Name), and preserves any locally stored API keys so you do not lose your per-workspace credentials. Workspaces that exist locally but not on the server are left untouched — sync never deletes.

OAuth tokens have a 72-hour lifespan with refresh; if sync reports an auth error, run cmdop login again.

Per-call overrides

Every cmdop connect subcommand accepts overrides that bypass the active workspace for that one invocation:

# Use a different stored workspace just for this call. cmdop connect --workspace staging vps-bmw # Inject a raw API key. cmdop connect --api-key ck_live_xxxxx exec prod-api-1 -- uptime # Point at an alternate gRPC relay. cmdop connect --server grpc.cmdop.internal:443 --list

These overrides are most useful for CI scripts, multi-tenant tooling, and support sessions where you do not want to touch the operator’s saved state. They are fully described in credential-resolver.

Per-workspace API key management

A workspace’s API key is treated as a discrete piece of state. You can inspect it, rotate it, or remove it without recreating the workspace:

# Show the active workspace's key (masked). cmdop connect key get # Replace it. cmdop connect key set ck_live_new_token # Remove it (forces fall-through to env / OAuth on next call). cmdop connect key clear

cmdop connect set-key <key> is kept as a deprecated alias to cmdop connect key set <key> and prints a notice steering you to the new form. See internal/connect/CLAUDE.md for the full surface.

Workspace migration on the server

When a logged-in user changes the active workspace in the web cabinet, the server side notices the new workspace_id in the next OAuth-bearing call and migrates the machine record from the old workspace to the new one. This is what lets you sign up under a personal workspace, then move a machine into a team workspace later without re-running cmdop agent register.

The CLI never has to do anything special — it picks up the new workspace on the next sync (or whenever the dashboard updates the OAuth token).

When to use multiple workspaces

A few patterns we see often:

  1. Production / staging split. Two workspaces with different relay accounts so a misconfigured CI job cannot accidentally reach production.
  2. Multi-tenant consultancy. One workspace per customer, switched per engagement. OAuth + sync keeps the list current.
  3. Personal vs company. A personal workspace for your own laptop, plus a team workspace shared with co-workers.
  4. On-prem relay. Set Workspace.Server for an internal relay (everything else stays on the default cloud relay).

The precedence chain that turns CLI flags, env vars, and stored workspaces into a single resolved API key.

How machines are scoped to a workspace and how the resolver picks one.

Workspace credentials versus per-machine passwords — they are different layers.

The full CLI surface for cmdop connect workspace and friends.

Last updated on