Remotes

A remote is a machine you connect to inference with belt remote. It hosts agent harnesses and, when you opt in, runs commands the platform dispatches.

The daemon connects outbound to inference over an authenticated WebSocket. Nothing listens on your machine, and the daemon runs only what the server sends.


When to use a remote

Use caseWhat the remote provides
Agent harness hostingKeeps coding agents (Claude Code, Codex, Cursor, and similar) logged in on a machine inference can drive
Command executionRuns shell commands on a connected host and streams stdout/stderr back (belt remote exec)

A remote is not a private inference engine. Engines run GPU/CPU workloads from the task queue. Remotes host harnesses and optional shell execution on a machine you control. See Private workers for compute on your hardware.


Security model

  • Outbound only. The daemon dials wss://api.inference.sh/ws/remotes/{id} with your API key. No inbound ports are opened.
  • Your OS user. Commands run as the user who started belt remote. That user is the blast radius.
  • Exec is opt-in. Command execution is disabled unless you start the daemon with --exec. Without it the daemon refuses remote_exec_start frames, and the API refuses the dispatch with 403 exec_disabled.
  • Destructive CLI gate. belt remote exec prompts for confirmation, or requires --yes in non-interactive mode.

Run the daemon under a dedicated user or inside a container if you need a smaller blast radius.


Connect a machine

Prerequisites

  • Belt CLI installed and logged in (belt login)
  • An API key or session with the remotes:write scope. The standard key preset includes it.

Start the daemon

bash
1belt remote

On start, belt:

  1. Creates or loads a machine identity key (remote_ed25519) in ~/.inferencesh/. When BELT_CONFIG_DIR is set, the key lives in that directory instead. The private key stays on the machine; only the public key is sent.
  2. Probes the machine for installed agent harnesses (see Harness discovery)
  3. Registers the remote with POST /remotes, sending the name (default: hostname), public key, belt version, system info, and probe results
  4. Connects to the remote WebSocket and sends a heartbeat every 5 seconds
bash
1belt remote --name "work-laptop"    # custom display name2belt remote --exec                  # allow command execution on this host

Press Ctrl-C to disconnect. The remote moves to disconnected once its heartbeat goes stale, and back to running when the daemon reconnects.

With --exec, registration sends exec_enabled: true and the daemon accepts command-dispatch frames. Without it, the status output shows exec: disabled.

System info

Registration includes a best-effort snapshot of the host in system_info:

FieldMeaning
hostnameMachine hostname
osOS label: the distro PRETTY_NAME on Linux, macOS on macOS, otherwise the Go OS name
cpusOne entry with name, cores, and frequency
ram.totalTotal physical memory in bytes

A probe that fails reports a zero value. Registration does not fail because of it.

Harness discovery

The daemon probes the host for known agent harnesses and sends the results in the harnesses field of POST /remotes. Each entry describes one harness binary found on PATH:

FieldMeaning
kindHarness identifier (for example claude-code, codex, cursor)
commandResolved path to the harness binary
versionFirst line of <command> --version. Best effort, may be empty.
logged_intrue when a vendor auth file exists. It does not prove the harness is usable.

Probes run concurrently. Each --version call has a 3 second timeout.

Supported harness kinds:

kindBinary looked upAuth file checked (existence only)
claude-codeclaude~/.claude/.credentials.json or ~/.claude.json
codexcodex~/.codex/auth.json
geminigemini~/.gemini/oauth_creds.json
cursorcursor-agent~/.cursor/cli-config.json
opencodeopencode~/.local/share/opencode/auth.json
ampamp~/.config/amp/settings.json

Discovery never reads credential files. logged_in comes from os.Stat on the auth path. File contents are not opened or transmitted.

Harnesses not in the table are omitted from registration.

The API exposes harnesses as profiles on each remote (harness_kind, command, status). On every POST /remotes the server reconciles the harnesses payload into profiles, one per harness kind. A harness with logged_in: true becomes idle; without it the profile is unavailable. If a harness disappears from the host, its profile stays and becomes unavailable.

Registration keys on the machine's public_key. Restarting belt remote on the same host updates the existing remote and its profiles. It does not create a duplicate. GET /remotes/{id} returns the same profiles array.


Run a command

Dispatch a command to a connected remote and stream its output:

bash
1belt remote exec <remote-id> -- ls -la2belt remote exec <remote-id> -- bash -c "echo hi && uname -a"
FlagPurpose
--cwd <path>Working directory on the remote
--timeout <seconds>Kill the command after N seconds (0 = no limit)
--ptyRun under a pseudo-terminal

The remote must have been started with belt remote --exec. Otherwise the API returns 403 exec_disabled.

belt remote exec is marked destructive and prompts for confirmation before dispatching. In CI or scripts, pass --yes / -y, or call the REST API directly.

Exit behavior. belt exits with the remote command's exit code when the run status is exited. Runs that end as killed or denied print an error and exit 1.


REST API

For automation, use the exec API:

  1. POST /remotes/{id}/execs creates a run
  2. GET /execs/{id}/output?after_seq=N returns sequenced stdout/stderr chunks
  3. GET /execs/{id} returns the run status
  4. POST /execs/{id}/signal cancels a running exec

These calls need the remotes:read and remotes:write scopes. Full reference: Remotes API and Exec Runs API.


Troubleshooting

SymptomLikely cause
not logged inRun belt login or set INFSH_API_KEY
exec_disabledRestart the daemon with belt remote --exec
remote_offlineThe daemon is not connected. Start belt remote on the host.
Run ends as deniedThe API could not deliver the command to the daemon
Run ends as killed with command execution is disabled on this remoteThe daemon refused the run. Restart it with --exec.
No outputPoll /execs/{id}/output with an increasing after_seq cursor

Next

CLI setup: command table and automation notes

Remotes API: register, list, update, and delete remotes

Exec Runs API: dispatch commands and read output

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.