Install a runner
One command installs a runner, and it is the same command on Linux and macOS.
curl -fsSL https://github.com/commandchain-ai/commandchain-runner-dist/releases/latest/download/install.sh | shThat installs the runner and then runs it right there in the terminal, on the runner screen, which shows the pairing code, what the runner found on the machine, and anything left to do. Nothing is installed as a background service, so the runner stops when you press Ctrl-C or close the window, and commandchain-runner starts it again.
This is also the only way to run a runner on a machine with no user service manager, such as a container or WSL without systemd.
Keep it running
Section titled “Keep it running”curl -fsSL https://github.com/commandchain-ai/commandchain-runner-dist/releases/latest/download/install.sh | sh -s -- --service--service installs the same runner as a background service that starts with the machine and keeps working after you close the terminal. It is what a machine doing real work ends up on. Run it whenever you are ready, including on a machine where you already ran the command above.
Either command pairs the machine with the hosted CommandChain. If you run CommandChain yourself, add --server https://your-commandchain.
Opening Settings, then Runners, then Add runner in the app always shows the exact command for the workspace you are looking at.
The installer needs no administrator rights and no runtime. There is no Node, no npm, no Docker, no build step, no GitHub account, and no token to paste. Every asset it fetches, the installer itself, the four executables, and their SHA256SUMS, comes from a public release mirror that accepts no credential.
Options
Section titled “Options”--server <url> The instance to pair with. Default: the hosted CommandChain API. Pass it only if you run CommandChain yourself.--display-name <name> How this machine appears in CommandChain. Default: user@host.--version <tag> Release to install, for example v1.2.0. Default: latest.--prefix <dir> Where the program goes. Default: $HOME/.local/bin.--status Show what is installed, where the logs are, and whether it runs.--uninstall Stop and remove the service and the program.--purge With --uninstall: also delete pairing credentials and workspaces.--skip-agent-login Do not sign the runner in to a coding agent during install. The runner installs and runs either way. To sign it in later, open it with "commandchain-runner" and follow its prompt, or run "commandchain-runner signin --agent claude-code".--service Install a background service that starts the runner with the machine and keeps it working after you close the terminal. Without it, the default, the runner is installed and then run in this terminal, where it pairs on its own screen and stops when you close the window. The default is also the only mode that works on a machine with no user service manager.--help This text.What just happened
Section titled “What just happened”The installer prints each step as it does it. Here is a real run, on a machine that had nothing installed:
$ curl -fsSL https://github.com/commandchain-ai/commandchain-runner-dist/releases/latest/download/install.sh \ | sh -s -- --server https://your-commandchain --display-name maya-macbook
CommandChain self-hosted runner (installer 0.1.2) machine linux-x64 server https://your-commandchain prefix /home/maya/.local/bin
1. Downloading the runner (linux-x64) from https://github.com/commandchain-ai/commandchain-runner-dist/releases/latest/download ✔ downloaded commandchain-runner-linux-x64 and SHA256SUMS
2. Verifying the checksum before anything is executed ✔ sha256 1a5389db3a465dd069489aa4dd3833b46beabf185dd88d49d79999d6d1747ab9 matches SHA256SUMS
3. Installing to /home/maya/.local/bin/commandchain-runner ✔ installed commandchain-runner 0.1.2
4. Installing the Claude Code CLI (native build - no Node required) ✔ claude at /home/maya/.local/bin/claude (2.1.218 (Claude Code))
5. Checking that this machine can contain a coding agent
commandchain-runner doctor - containment check host type self_hosted provider linux-landlock platform linux tier landlockOK - every agent process on this machine will run inside this boundary. ✔ containment established (see the report above)
6. Pairing with CommandChain (https://your-commandchain)
──────────────────────────────────────────────────────────── Pair this runner to approve it for a tenant:
Code: 329X-4QKT URL: https://app.your-commandchain/app/pair?code=329X-4QKT
Waiting for approval (up to 10 min)...────────────────────────────────────────────────────────────
✔ Paired with CommandChain. instance https://your-commandchain tenant alpenglow runnerId 32c152e4-3d5e-49a1-b3df-20b95c0a74b6 displayName maya-macbook credential /home/maya/.commandchain/runner.json (0600, never printed)
7. Coding agent sign-in for this runner Signing this runner in to Claude Code. Your browser opens; this sign-in belongs to the runner and never leaves this machine. ✔ The runner is signed in to Claude Code. Nothing is uploaded.
8. Installing the user service ✔ wrote /home/maya/.config/systemd/user/commandchain-runner.service ✔ commandchain-runner is running and will restart itself if it stops
Done ✔ the runner is installed, paired, contained, and running as a user service
open: commandchain-runner (the runner screen: status, sign-in, and anything left to do) status: sh install.sh --status logs: /home/maya/.local/state/commandchain-runner/runner.log uninstall: sh install.sh --uninstallStep by step:
-
Download. One executable, chosen for your operating system and CPU, plus the release’s
SHA256SUMS. -
Verify. The checksum is checked before anything is executed. A mismatch stops the install.
-
Install the program. Into
~/.local/binby default, or wherever--prefixsays. -
Install the coding agent. Claude Code’s own native build, which also needs no Node.
-
Prove containment. The installer runs
doctor, which builds a real sandbox policy and runs a real process through it. If this machine cannot contain an agent, the install stops here and points you at a managed runner. There is no flag that turns this into a warning. -
Pair. A device code, approved in your browser. See pairing.
-
Coding agent sign-in for this runner. With a terminal, Claude Code’s own browser sign-in runs for the runner, into
~/.commandchain/agent-auth. Nothing is uploaded, and your own sign-in is not touched. With no terminal, or with--skip-agent-login, open the runner later withcommandchain-runnerand follow its prompt. See sign-in only or full setup. -
Install the service. A user-level service, started immediately, restarted if it stops.
Where the files go
Section titled “Where the files go”Nothing is installed outside your home directory, and nothing asks for sudo.
| What | Where |
|---|---|
| The program | ~/.local/bin/commandchain-runner |
| Pairing credential, workspaces, the runner’s own sign-ins | ~/.commandchain (mode 0700). COMMANDCHAIN_RUNNER_STATE_DIR moves all of them |
| The service | ~/.config/systemd/user/ on Linux, ~/Library/LaunchAgents/ on macOS |
| Logs | ~/.local/state/commandchain-runner/ on Linux, ~/Library/Logs/commandchain-runner/ on macOS |
The pairing credential is written to a 0600 file. It is never printed, never a command-line argument, and never written into the service definition.
Starting it again
Section titled “Starting it again”A runner installed the default way stopped when you closed that terminal. Start it again with one command, from a terminal on that machine:
commandchain-runnerThat is also how you open the runner screen for a runner that is already running in the background: it attaches to the running one rather than starting a second, shows its status and anything left to do, and closing it leaves the background service running.
A background-service install starts itself with the machine, so usually there is nothing to do. When the app says that runner is offline or stale, start the service from a terminal on that machine.
On Linux:
systemctl --user reset-failed commandchain-runner 2>/dev/null; systemctl --user restart commandchain-runnerreset-failed matters. A runner holding a credential the workspace no longer
accepts exits immediately, so systemd stops retrying it and parks the unit in a
failed state, where a plain restart answers Start request repeated too quickly
and does nothing. On a healthy unit it does nothing at all.
On macOS:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.commandchain.runner.plist 2>/dev/null \ || launchctl kickstart -k gui/$(id -u)/ai.commandchain.runnerBoth commands work whether the service is stopped or already running: they load it if it is unloaded and restart it if it is not. The runner comes back online in the app within a few seconds. If it does not, read the log, because a runner that starts and exits says why in its first lines:
tail -f "${XDG_STATE_HOME:-$HOME/.local/state}/commandchain-runner/runner.log" # Linuxtail -f ~/Library/Logs/commandchain-runner/runner.log # macOSRunning the install command again is safe too. It reuses the pairing and credentials this machine already has, so it does not create a second runner. For the same reason it cannot fix a credential the workspace has stopped accepting: open the runner with commandchain-runner and press enter to pair again (or run commandchain-runner connect --force-pair --pair-only), then the start command above once more. See troubleshooting.
To stop it, use systemctl --user stop commandchain-runner on Linux or launchctl bootout gui/$(id -u)/ai.commandchain.runner on macOS. Both are temporary: the service comes back at the next login. To remove it for good, see upgrades and uninstall.
Keeping it running after you log out
Section titled “Keeping it running after you log out”On Linux the service runs while you are logged in. To keep it running afterwards, enable lingering for your own user:
loginctl enable-linger "$USER"Next steps
Section titled “Next steps”- The runner screen: status, sign-in, and anything left to do.
- Pairing: the browser approval, in detail.
- Upgrades and uninstall: day-2 operations.
- Troubleshooting: when one of the steps above stops.