Edge nodes — run jobs on your own machine
Turn a machine you own into a Spike Edge Node: a one-command bootstrap for a fresh Linux box or EC2 instance, the manual path for an existing machine, how to attach it to a cluster, and the agent-side API.
An edge node is a computer you own running a Spike worker. It pulls jobs from Spikefrost, executes them locally with your own Claude Code or Codex seat, and streams the result back into the conversation that asked for it.
Reach for one when the work has to happen on your hardware: a private repository, an internal network the cloud can't route to, a machine that already holds the credentials and tooling. As a side effect, the model usage bills to your own coding-agent account rather than your Spikefrost balance.
Fast path — a fresh Linux box or EC2 instance
One command as root turns a clean machine into a ready node:
curl -fsSL https://edge.spikefrost.com/sf/ec2-bootstrap.sh | sudo bash
Works over SSH on any systemd distribution, and works equally as cloud-init user-data pasted at instance launch — the instance comes up with the node already running.
It installs and configures, in order:
git— a hard requirement of every snapshot task. Amazon Linux ships without it.- The
codexCLI (via npm) and theclaudeCLI (Anthropic's native installer, per-user). Aclaudefailure is non-fatal: codex-only nodes work fine. - The Spikefrost CLI and edge runner, which bring their own Node runtime.
loginctl enable-linger— see below. This is the step people miss.- The systemd user service, registered and started, surviving logout and reboot.
It finishes by printing the node's connection string and a next-steps banner.
The linger trap
Worth stating on its own, because it is the single most common support issue with Linux nodes:
Without
loginctl enable-linger, systemd terminates your user service when the last SSH session closes. The symptom is distinctive: the node works perfectly all day while you are connected, and is offline the next morning.
The bootstrap enables it. If you set a machine up by hand, or inherited one that keeps disappearing, check it:
loginctl show-user $USER --property=Linger
Linger=yes is what you need. Anything else and the node will not survive your logout.
Two things the bootstrap deliberately does not do
Both are per-customer and interactive by design — the machine runs your own AI seat, so no script can do them for you.
1. Sign in to the AI CLI, as the user the service runs as:
codex login --device-auth
claude setup-token
Either is enough; the node uses whichever provider an agent asks for.
2. Attach the node to a cluster — the console step described next.
Sizing
| Guidance | |
|---|---|
| RAM | Codex at high or xhigh effort against a real repository wants 2 GB or more — t3.medium and up |
| Disk | Workspaces accumulate per conversation, so size generously rather than tightly |
Existing machine — step by step
For a Mac, or a Linux box you already run and would rather configure yourself. Install the CLI first if you haven't:
curl -fsSL https://edge.spikefrost.com/sf/install.sh | sh
Then print the node's connection string:
sf edge pair
Run the worker in the foreground to watch the startup checks:
sf edge run --verbose
Once it looks right, install it as a background service. This survives a restart, starts on login, and keeps the machine awake so dispatched jobs aren't missed:
sf edge service start
status, stop and restart do what you'd expect, and start installs the service first if it isn't installed yet. On Linux, remember linger.
Attaching the node to a cluster
This applies to both paths, and the direction matters — it is the opposite of what most people assume:
The machine prints its connection string. The console receives it. There is no code issued by the console that you type on the machine.
- In the console open Connectors and add a Spike edge node connector, or open the one you already have. The connector is the cluster — one connector holds several machines, and agents address the cluster, so you can add hardware later without touching agent code.
- Choose Add node and paste the connection string the machine printed.
The string looks like spike-edge-node://connect?token=…, and you can re-print it at any time:
sf edge pair
Treat it as a credential. It carries the node's pairing token, so don't paste it into a ticket, a chat channel, or anywhere you wouldn't paste a password. Rotate it whenever you need to:
sf edge regenerate-token
Verify it is working
Three commands, in the order worth running them:
sf edge status
sf edge logs --lines 20
You are looking for Gateway accepted edge-node session in the log. And on Linux:
loginctl show-user $USER --property=Linger
One log line deserves recognition rather than debugging:
Connected, but this node is NOT paired to a cluster yet — its pairing token is not registered.
That means the runner reached Spikefrost but its connection string was never added to a cluster. Finish the console step; the node binds itself on the next retry.
Give the cluster its environment
Variables set on the cluster are handed to every execution on every node in it — the right home for an internal API base or a key the jobs need locally:
sf edge env list
sf edge env set API_BASE https://internal.example.com
Using it from an agent
The machine becomes an agent's tool. Declare it on the agent class:
override tools = {
workstation: this.edgeComputerTool({
alias: 'my_mac_mini', // the connector — i.e. the cluster
provider: 'claude', // or 'codex'
repos: [ // mounted beside the app, always pulled
{ provider: 'github', fullName: 'acme/api' },
],
}),
};
Five behaviours decide whether your design works. They are not edge cases:
The turn ends at dispatch. The tool returns "started", not a result. The machine then works alone for minutes and the answer arrives later as a new message in the same conversation. Never await it, poll it, or re-dispatch — holding the turn open produces duplicate replies.
Dual mount, always fresh. The app's own code is always checked out, every declared repository beside it, and all of them pulled before the CLI starts. A tree with uncommitted work from a previous turn is not pulled — the agent is told so in its preamble rather than losing the work.
Two push verbs. sf app push publishes app code; git push publishes a mounted repository. The machine publishes neither on its own, and its workspace persists — so ending a turn mid-refactor is normal and safe.
The session is the conversation. Follow-up instructions resume the same CLI session on the machine, so the agent can refer back to earlier work. A different conversation gets a fresh session.
One job per computer and app. A second command for the same app while one is running is rejected with a typed error. Relay that to the user in plain language rather than retrying. A different app on the same computer runs concurrently.
And the constraint that shapes the prompt: no progress, no steering, no cancel mid-run. Describe the outcome you want, not the keystrokes, and expect nothing back until it finishes.
What the machine can reach
The node's access is yours to bound, and the defaults are conservative:
| Control | Default | Effect |
|---|---|---|
--workspace-root <path> |
— | Allowlist of directories the node may work in. Repeatable |
--no-ai-cli |
AI enabled | Disables agent execution entirely — the node still handles other local actions |
--max-tasks <n> |
5 | Concurrent local actions |
--max-runtime-ms <ms> |
— | Hard ceiling on a single local action |
--max-output-bytes <n> |
— | Caps inline stdout/stderr captured back |
Beyond that: a node only ever executes jobs dispatched to its own cluster, the pairing token is rotatable, and the credentials the work uses are the ones already on your machine — Spikefrost never sees your Claude or Codex login.
Configuration reference
Every flag has an environment-variable equivalent, which is usually the better choice for a background service.
| Flag | Environment variable |
|---|---|
--gateway-url <url> |
SPIKE_EDGE_GATEWAY_URL |
--workspace-root <path> |
SPIKE_EDGE_WORKSPACE_ROOTS |
--no-ai-cli |
SPIKE_EDGE_ALLOW_AI_CLI=0 |
--max-tasks <n> |
SPIKE_EDGE_MAX_TASKS |
--no-cli-health-check |
SPIKE_EDGE_CLI_HEALTH_CHECK=0 |
--cli-health-timeout-ms <ms> |
SPIKE_EDGE_CLI_HEALTH_TIMEOUT_MS |
--no-auto-upgrade |
SPIKE_EDGE_AUTO_UPGRADE=0 |
--auto-upgrade-interval-ms <ms> |
SPIKE_EDGE_AUTO_UPGRADE_INTERVAL_MS |
--verbose |
SPIKE_EDGE_VERBOSE=1 |
--stream-output |
SPIKE_EDGE_STREAM_OUTPUT=1 |
--stream-agent-events |
SPIKE_EDGE_STREAM_AGENT_EVENTS=1 |
--no-reconnect |
— |
sf edge help prints the complete list, including the upgrade-source overrides.
Keeping it current
sf edge version
sf edge upgrade
The runner checks for upgrades while idle by default. Pin the version on a machine where you don't want that, with --no-auto-upgrade or SPIKE_EDGE_AUTO_UPGRADE=0. Add --force to reinstall at the same version.
Troubleshooting
| Symptom | Cause |
|---|---|
| Node offline the morning after it worked all day | systemd linger is off. loginctl show-user $USER --property=Linger must say Linger=yes |
| "Connected, but this node is NOT paired" | The connection string was never added to a cluster. Finish the console step; it binds on retry |
| Looking for a pairing code to type in | There isn't one. The machine prints a connection string and the console receives it |
| Startup stalls on CLI checks | The node says hello to Claude/Codex on boot. If that seat isn't signed in, sign in — or skip the probe with --no-cli-health-check |
| Tasks fail on a fresh Amazon Linux box | git is missing. The bootstrap installs it; a hand-built machine needs it added |
| Jobs run out of memory | Codex at high effort wants 2 GB+. Move up an instance size |
| Dispatch rejected with a typed error | Another job is already running for that computer and app. Wait, or dispatch to a different app |
| Jobs never arrive | Check sf edge status, and that the agent's alias matches the connector |
| Work not visible in the repository | The machine doesn't auto-publish. Use sf app push for app code or git push for a mounted repository |
| Agent describes work that didn't happen | Read the trace, not the reply — see Observability and costs |
Next
- Tools and data — the rest of what an agent can be granted.
- The sf CLI — installing and signing in.
- Download — get the CLI and the desktop app.
Frequently asked questions
What is an edge node?
A computer you own running a Spike worker. It pulls jobs from Spikefrost, executes them locally using your own Claude Code or Codex seat, and streams results back. The work happens on your hardware, with your credentials and your network access.
What is the fastest way to stand one up?
On a fresh Linux box or EC2 instance, one command as root installs and starts everything, then prints the node's connection string. You paste that string into your edge cluster in the console and sign in to your AI CLI. Nothing else is required.
Why did my node go offline overnight?
Almost certainly systemd linger. Without it, the user service is killed when your last SSH session closes — so the node works all day and is gone the next morning. The bootstrap enables it for you; check it with loginctl show-user $USER --property=Linger.
Does the node bill against my Spikefrost balance?
No. The machine runs your own Claude or Codex seat, so that usage bills to that account. Spikefrost dispatches the work and carries the result.
Do I paste a code into the machine, or a string into the console?
A string into the console. The machine generates and prints its own connection string; the console's edge cluster receives it via Add node. There is no code issued by the console that you type on the machine.
How big does the instance need to be?
Codex at high or extra-high effort against a real repository wants 2 GB or more of RAM, so t3.medium and up. Workspaces accumulate per conversation, so give the disk more room than feels necessary.