Reference

Agent reference

Installation, enrollment, services, updates, tmux, and storage.

A single self-contained Go binary. Put it on the machine, then enrol it.

Install the binary

Option A — install script (downloads the latest release). It detects the machine's OS and architecture, picks the matching release asset, and installs to /usr/local/bin:

curl -fsSL https://raw.githubusercontent.com/sidhantpanda/spectre/main/scripts/install-agent.sh | sudo bash

Given a --host it enrols the machine too, so install and connect are one line:

curl -fsSL https://raw.githubusercontent.com/sidhantpanda/spectre/main/scripts/install-agent.sh \
  | sudo SPECTRE_AUTHKEY=sk_... bash -s -- --host wss://spectre.example.com
FlagEnvironmentDefaultPurpose
--host <url>SPECTRE_HOSTControl server to enrol with. Omit to install the binary only.
--authkey <key>SPECTRE_AUTHKEYAuth key from the UI. Omit and the agent prints a code to approve.
--tag <vX.Y.Z>TAGlatest releaseWhich release to install.
--bin-dir <dir>BIN_DIR/usr/local/binWhere to put the binary.

Prefer SPECTRE_AUTHKEY over --authkey: a flag is visible in ps to every user on the machine for as long as the command runs. The script passes the key to the agent through the environment either way, so the agent's own process never exposes it.

Supported assets are linux/amd64, linux/arm64, darwin/amd64, and darwin/arm64. A 32-bit Pi (armv7l) has no published build — use Option B.

Option B — build it here and copy it to a machine on your network. This is the usual path for a home lab or LAN box: cross-compile on your dev machine, scp the binary over, and enrol it against your local server. No published release needed.

1. Find the target's OS and architecture. Go cross-compiles to a specific GOOS/GOARCH pair, so you need to know what the target machine is. If you can reach it, ask it:

ssh <user>@<remote> 'uname -sm'
# "Linux x86_64"   -> GOOS=linux  GOARCH=amd64
# "Linux aarch64"  -> GOOS=linux  GOARCH=arm64   (Raspberry Pi OS 64-bit, etc.)
# "Linux armv7l"   -> GOOS=linux  GOARCH=arm     (older 32-bit Pi)
# "Darwin arm64"   -> GOOS=darwin GOARCH=arm64   (Apple Silicon Mac)
# "Darwin x86_64"  -> GOOS=darwin GOARCH=amd64   (Intel Mac)
uname -smGOOSGOARCHTypical target
Linux x86_64linuxamd64Most servers, Intel/AMD NUCs
Linux aarch64linuxarm64Raspberry Pi (64-bit), ARM servers
Linux armv7l / armv6llinuxarmRaspberry Pi (32-bit), older SBCs
Darwin arm64darwinarm64Apple Silicon Mac
Darwin x86_64darwinamd64Intel Mac

2. Build for that target. From agent/:

cd agent
GOOS=linux GOARCH=arm64 go build -o spectre-agent .   # e.g. a 64-bit Raspberry Pi

CGO_ENABLED=0 is the default here, so the binary is static and has no libc dependency — it runs on any machine of that arch, including minimal or musl-based distros.

3. Copy it to the target and install it. scp cannot write to /usr/local/bin directly (it's root-owned), so land it in a writable spot first, then move it into place:

scp spectre-agent <user>@<remote>:/tmp/

ssh <user>@<remote>
sudo install -m 0755 /tmp/spectre-agent /usr/local/bin/spectre-agent && rm /tmp/spectre-agent

4. Enrol it against your server. On the target, point --host at your control server. On a LAN without TLS that's plaintext ws:// to the server's IP and the published proxy port; the agent appends /api/agents/register itself:

# Interactive — prints a code to approve in the web UI:
sudo spectre-agent up --host ws://<server-lan-ip>:3000

# Or with an auth key from the UI:
sudo spectre-agent up --host ws://<server-lan-ip>:3000 --authkey sk_...

ws:// vs wss://: a bare host or wss:// uses TLS. Plaintext ws:// to anything other than localhost logs a loud warning, because terminal I/O and the device key travel unencrypted. On a trusted home LAN that may be an acceptable trade-off; over the internet, always put the server behind a TLS proxy and use wss://.

To rebuild after pulling changes, repeat steps 2–3 — the installed binary is replaced in place and the stored device key in ~/.spectre-agent (or /var/lib/spectre-agent) is reused, so there's no need to re-enrol.

Enrol and run

# With an auth key from the UI (non-interactive):
sudo spectre-agent up --host wss://spectre.example.com --authkey sk_...

# Or interactively — prints a code to approve in the UI:
sudo spectre-agent up --host wss://spectre.example.com

up enrols the machine, stores the device key, installs a service, and starts it. The enrollment credential is never written into the service file: the agent enrols once, up front, and the service runs with only --host.

The key is written to the service's own state directory (/var/lib/spectre-agent, or SPECTRE_AGENT_HOME if you set it) and handed to the account the service runs as — the same place the service reads it from. A machine you had already enrolled by hand keeps its device key: up carries it over rather than enrolling the machine a second time.

TLS: a bare host (--host spectre.example.com) defaults to wss://. Plaintext ws:// to anything other than localhost logs a loud warning — terminal I/O and the device key would be exposed to the network.

Run as a daemon

Linux (systemd)macOS (launchd)
Service file/etc/systemd/system/spectre-agent.service/Library/LaunchDaemons/com.spectre.agent.plist
View logsjournalctl -u spectre-agent -ftail -f /var/log/spectre-agent.log
Device data/var/lib/spectre-agent//var/lib/spectre-agent/

No root / can't install a service? Run it directly — it only writes to ~/.spectre-agent and needs no privileges:

setsid spectre-agent run --host wss://spectre.example.com --authkey sk_... >~/spectre-agent.log 2>&1 &

It enrols exactly like the service and tmux sessions still persist; it just won't survive a reboot.

Commands and flags

spectre-agent status              # running state, pid, device id, service status
sudo spectre-agent up --host ...  # enrol, install as a service, and start
spectre-agent update              # upgrade to the latest release, in place
sudo spectre-agent down           # stop and remove the service
sudo spectre-agent down --purge   # also delete the device key
spectre-agent run --host ...      # run in the foreground (Ctrl+C to stop)

Updating an agent

Two ways: from the dashboard, or on the machine itself.

From the dashboard. The control server checks GitHub hourly for the newest agent release. Any connected machine running something else shows an Update to vX.Y.Z button in the machine list. Clicking it sends the request down that machine's existing socket; the agent downloads the release, swaps its binary, and exits — systemd's Restart=always then starts it again on the new build. The button reads Updating… until the machine reconnects reporting the new version, which is the real confirmation it worked.

The agent exits rather than calling systemctl restart on itself: a service restarting its own unit needs privileges the service account does not have, and the exit achieves the same thing for free.

Where the binary lives. Replacing a running binary means rename(2) — writing in place fails with ETXTBSY — and rename checks write permission on the directory, not the file. A sudo install puts the binary in root-owned /usr/local/bin but runs the service as the invoking user, which is exactly the combination that cannot replace itself. So up moves the binary to /var/lib/spectre-agent/bin/spectre-agent, hands that directory to the service account, and leaves a symlink at the original path:

/usr/local/bin/spectre-agent -> /var/lib/spectre-agent/bin/spectre-agent

One binary, still on PATH under its usual name, and the CLI and the service can never drift onto different versions. Nothing else about the host changes — no extra units, no sudoers entries. A service already running as root, or one whose binary sits somewhere it can already write, is left where it is.

down --purge deletes that state directory, so it copies the binary back to its original path first rather than leaving a dangling symlink.

The button only appears on connected machines — the request travels over the live socket, so an offline machine has nowhere to receive it. If the server cannot reach GitHub, no button appears at all rather than a guess. A failed update is reported back and shown on that machine's row, so it does not sit spinning.

On the machine.

spectre-agent update asks GitHub for the newest release, downloads the build for the machine's OS and architecture, replaces the binary in place, and hands the running agent over to it — no sudo required.

spectre-agent update --check         # is there a newer release? changes nothing
spectre-agent update                 # install the latest
spectre-agent update --tag v1.2.3    # pin a version, or roll back
spectre-agent update --force         # reinstall the version already running

It does not re-enrol. The device key lives in the agent's state directory, which the update never touches, so the machine keeps its identity and needs no new auth key — it reconnects as the same device it already was.

Notes:

  • Neither kind of update needs root. up has already put the binary somewhere the service account owns (see Where the binary lives above), and the restart is a signal, not a systemctl call: the CLI sends SIGTERM to the running agent, which shuts down cleanly, and Restart=always starts the new binary. Both the CLI and the control server take that route.
  • If the binary is somewhere you cannot write — a stock install where the service runs as root — the command stops before downloading anything and tells you to re-run with sudo.
  • The downloaded binary is run once before it is installed. A truncated download or a wrong-architecture asset fails there, leaving the working binary in place.
  • The swap is a rename within one directory, so it is atomic — an interrupted update never leaves a half-written agent behind. Replacing the file of a running process is safe on Linux and macOS; the old process keeps running until the service restarts.
  • Unauthenticated GitHub API calls are rate-limited per IP (60/hour). If you hit that, pass --tag to skip the lookup.
FlagDescription
--hostControl server URL. Required. wss://host (or a bare host, which defaults to TLS)
--authkeyAuth key from the UI. Omit to approve the machine interactively

Uninstall

curl -fsSL https://raw.githubusercontent.com/sidhantpanda/spectre/main/scripts/uninstall-agent.sh | sudo bash

Or, to remove just the service and its data (leaving the binary):

sudo spectre-agent down --purge

down leaves the binary in place. Delete it when you're done: sudo rm /usr/local/bin/spectre-agent.

Revoking the machine in the web UI is what actually cuts off access — uninstalling only stops the agent from reconnecting.

Persistent sessions via tmux

When tmux is installed, the agent wraps each terminal in a tmux session named spectre. Close the tab and reopen it and you're back where you left off; multiple tabs share the session. This survives browser disconnects, WebSocket drops, and server restarts. Without tmux, sessions are ephemeral.

sudo apt install tmux    # Debian/Ubuntu
sudo yum install tmux    # RHEL/CentOS
brew install tmux        # macOS

Data storage

  • Device ID and key: ~/.spectre-agent/device-info.json, mode 0600 (or /var/lib/spectre-agent/ as a service)
  • Lock file: /tmp/spectre-agent.lock (prevents duplicate instances; contains no secrets)

On this page