fredrin-agent — setup and pairing guide
fredrin-agent is the standalone daemon that runs Fredrin tickets on your own
always-on machine (a home server, a cloud VM, a spare Mac). It dials out to
Fredrin over Ably — no inbound ports, no VPN — receives dispatched tickets, runs
your coding CLI in an isolated per-ticket worktree, and streams the live
terminal back to the ticket UI.
You never need Fredrin's source code: the agent ships as a single self-contained bundle downloaded by the installer.
Prerequisites
On the machine that will run jobs:
- Node.js 20+ (includes
npm, which the installer uses to fetch a prebuilt terminal engine — no compiler or root required on common platforms). - GitHub CLI (
gh) installed and authenticated:gh auth login. Fredrin uses it to open PRs when Workers ship. - A supported coding CLI, installed. For Claude Code a machine with its
own sign-in just uses it (the local login always wins); a machine without one
— headless boxes and containers included — is covered by the workspace's
subscription token (minted once with
claude setup-token, stored in Settings → Models), delivered per-job. The other CLIs still need their own sign-in on the machine:- Cursor Agent —
agent login(default) - Claude Code —
claude /login, or no sign-in when the workspace has a subscription token - Codex CLI —
codex login(with ChatGPT) - GitHub Copilot CLI —
npm i -g @github/copilot
- Cursor Agent —
- A clone of your project repo on the machine — jobs run in worktrees created from this checkout. Note its path; you'll enter it during pairing.
curlorwget.
Run the agent as a non-root user (some CLIs, including Claude Code, refuse to run unattended as root).
1. Install
The quickest way is to let Claude Code do it for you. On the machine you want to run jobs (Claude Code is one of the supported coding CLIs, so it's often already there — or SSH into the machine first), paste this prompt into Claude Code:
Set up the Fredrin remote agent on this machine so it can run my Fredrin tickets. Do it for me end to end:
1. FIRST, before anything else, detect whether a Fredrin agent is already installed or running on this machine. An older, outdated `fredrin-agent` may already be present — if so you must fully stop and remove it before installing, NOT waste time rediscovering it later. It is present if ANY of these are true:
- `command -v fredrin-agent` succeeds — then run `fredrin-agent status` (it reports the running pid and whether a supervisor service is installed)
- a live process shows up: `pgrep -fl fredrin-agent`
- a supervisor unit exists: macOS `~/Library/LaunchAgents/com.fredrin.agent.plist` (launchd label `com.fredrin.agent`); Linux `~/.config/systemd/user/fredrin-agent.service`
- state files exist under `~/.fredrin/` (`agent.pid`, `agent.json`)
If NONE are present there is no existing agent — skip straight to step 2. If ANY are present, STOP and remove the old agent completely, including every process it spawned, in this exact order (a supervised agent restarts within seconds if you only `stop` it, so remove the supervisor FIRST):
a. Remove the supervisor so it stops respawning the daemon — this also tears down the whole supervised process tree: `fredrin-agent service uninstall`. If the launcher is missing or too old to have that verb, remove the unit by hand — macOS: `launchctl bootout gui/$(id -u)/com.fredrin.agent 2>/dev/null; rm -f ~/Library/LaunchAgents/com.fredrin.agent.plist` — Linux: `systemctl --user disable --now fredrin-agent.service 2>/dev/null; rm -f ~/.config/systemd/user/fredrin-agent.service; systemctl --user daemon-reload`.
b. Stop the daemon (this releases any in-flight jobs): `fredrin-agent stop`.
c. Sweep any survivors — orphaned children, in-flight job PTYs, self-update helpers: `pkill -f fredrin-agent; pkill -f '\.fredrin/agent'` (escalate stubborn ones with `pkill -9 -f fredrin-agent`).
d. Confirm the machine is clear before continuing: `pgrep -fl fredrin-agent` must print NOTHING. Do NOT delete `~/.fredrin/agent.json` — keeping those credentials lets the updated agent re-pair cleanly.
2. Check the prerequisites and install anything missing: Node.js 20+ (with npm) and the GitHub CLI `gh` signed in via `gh auth login`. Run everything as a non-root user. For the Claude runtime a machine with a signed-in Claude Code just uses that login; a machine without one is covered by the workspace's subscription token, delivered per-job (the pairing flow checks one exists). Only if I plan to run Cursor or Codex tickets on this machine does that CLI need its own sign-in.
3. Install (or update) the agent by running the official installer — it downloads the CURRENT self-contained bundle and puts a `fredrin-agent` launcher on my PATH, replacing any older bundle:
curl -fsSL https://www.fredrin.com/install.sh | sh
(use `wget -qO- https://www.fredrin.com/install.sh | sh` if curl isn't available)
4. Verify it installed by running `fredrin-agent status` and show me the output.
Then tell me the next step: pairing this machine with my workspace by running `fredrin-agent login` (I'll grab the pair code and workspace id from Settings → Remote pairing → Pair new agent). If this machine was already paired before the update, run `fredrin-agent restart` instead to bring the freshly-installed version online.
Claude Code first stops and removes any older fredrin-agent already on the box,
then checks the prerequisites, runs the installer, and confirms the agent is on
your PATH — then you pair it in step 2 below. In the Pair new agent
dialog, Fredrin hands you the same prompt with your pair code and workspace id
already filled in, so Claude Code installs and pairs in one paste.
Prefer to run it yourself? The installer is a plain one-liner:
curl -fsSL https://www.fredrin.com/install.sh | sh
Either way, this downloads the bundled agent to ~/.fredrin/agent/, installs the
prebuilt terminal engine beside it, and puts a fredrin-agent launcher on your
PATH (via /usr/local/bin when writable, otherwise ~/.fredrin/bin — the
installer prints which). It also warns if claude or gh are missing.
2. Pair with Fredrin
-
In Fredrin, open Settings → Remote pairing and click Pair new agent. The dialog shows an 8-character pair code (like
ABCD-EFGH) and your workspace id — both with copy buttons. -
On the machine, run:
fredrin-agent loginYou'll be prompted for:
- Pair code — from the dialog (codes expire; generate a fresh one if needed)
- Workspace id — from the same dialog
- Repo root — optional; press Enter to accept the default. Pairing is
machine-wide: the agent serves every project in the workspace and clones
each project's repo on demand (a local checkout is only reused when its
originmatches the ticket's project), so there is no project to pick here
Scripting it? On a machine nobody is typing at — a provisioning script, an SSH one-liner, a Claude Code session — pass the answers as flags instead, and the prompts are skipped entirely:
fredrin-agent login --code ABCD-EFGH --workspace your-workspace-id(
FREDRIN_PAIR_CODE/FREDRIN_WORKSPACE_IDin the environment do the same.) Do not try to pipe answers into the interactive prompts: a pipe hits EOF, readline drops everything after the first line, andloginexits 0 having paired nothing. -
On success,
logininstalls the agent as a service (a launchd LaunchAgent on macOS, a systemd user unit on Linux) so it starts at boot/login and restarts within seconds of a crash — and starts it. On an interactive terminal it asks first (default Y); non-interactive logins install without asking. Pass--no-serviceto skip and manage the process yourself. -
The dialog confirms the moment pairing succeeds, and the machine appears in the Remote pairing list.
Credentials are stored at ~/.fredrin/agent.json (mode 0600). The server URL
is always www.fredrin.com; FREDRIN_URL exists only as a dev/preview override.
3. Manage the running agent
After login the agent is already running under supervision — there is no separate start step. Manage it with:
fredrin-agent status # running? paired as what? where are the logs?
fredrin-agent logs # last 200 log lines (-f to follow)
fredrin-agent restart # supervised: supervisor respawns it; bare: stop + start
fredrin-agent stop # graceful shutdown (releases in-flight jobs)
If you opted out with --no-service, fredrin-agent start from an interactive
terminal detaches into the background and returns immediately — closing the
SSH session doesn't stop it. Nothing restarts a bare daemon after a crash,
and start says so on stderr.
Use fredrin-agent start --foreground to keep it attached (for debugging).
Under systemd or pm2 it detects the supervisor and stays in the foreground
automatically, so service units keep working unchanged.
The agent connects, probes which coding CLIs are installed, reports them to Fredrin, and waits for jobs. Pick the default CLI and model per workspace in Settings → Runtimes. When a ticket is dispatched to this machine, the agent creates a worktree and branch for the ticket, runs the configured CLI in a real interactive terminal, and streams output (and your typed input) through the ticket UI.
Restart the agent (fredrin-agent restart) after installing a new CLI or
running gh auth login, so it re-reports its capabilities.
Supervision (installed by login)
fredrin-agent login installs the service by default (see step 2 above). The
service verbs manage it directly — including installing later if you opted
out at login:
fredrin-agent service install # start at boot + restart on crash
fredrin-agent service status # supervisor state (plus plain daemon state)
fredrin-agent service uninstall # stop supervising; removes the unit
Logs still land in ~/.fredrin/agent.log (fredrin-agent logs). On Linux the
unit runs in your user session; service install prints the
loginctl enable-linger $USER command that makes it start at boot before
you log in. Re-running service install is safe — it regenerates the unit
with the current node/agent paths. Windows isn't supported yet; run
fredrin-agent start --foreground under Task Scheduler or NSSM instead.
Running under your own systemd system unit or pm2 still works unchanged — the
agent detects those supervisors and stays in the foreground.
(pm2 start fredrin-agent -- start also works.)
Self-update
Once installed, the agent keeps itself current: while idle it checks Fredrin for new builds, swaps in the new bundle atomically, and relaunches. You install once; there is no manual upgrade step.
Troubleshooting
- "Not paired. Run: fredrin-agent login" —
~/.fredrin/agent.jsonis missing or unreadable; re-runfredrin-agent login. - Pair code rejected — codes are short-lived. Generate a fresh one from Settings → Remote pairing → Pair new agent and retry.
- Terminal engine install fails — your platform may lack a prebuilt
node-ptybinary; install build tools and re-run the installer (Debian/Ubuntu:sudo apt-get install -y build-essential python3). - Jobs dispatch but the CLI hangs or PRs never open — check that the coding
CLI is signed in (
claude /login,agent login, …) andgh auth statuspasses as the user the agent runs as; logins are per-user. - A newly installed CLI isn't offered — restart the agent
(
fredrin-agent restart) so capabilities are re-probed.