Installing the daemon
From a machine with an agent CLI on it to a runtime showing online in Félagi. Running it as a service is the next page, Running as a service; this one gets it working in a terminal first, because a service you have never seen succeed in the foreground is a service you cannot debug.
What it is
One binary, felagi, that lives on the machine your coding-agent CLIs are installed on. It
registers that machine with a Félagi server, polls for work, prepares an isolated directory per
task, runs the CLI, and streams what happened back. It makes no product decisions and holds no
model key and no git credential: it uses whatever the CLI and git on this machine already have.
That last sentence is most of what there is to install. If a person, signed in as the user the daemon will run as, can do these two things:
claude -p "hello" # or: elyra -p "hello"
git clone git@github.com:acme/api.git # a private repository the agents will work in
then the daemon can. If they cannot, no amount of daemon configuration will help.
Requirements
| Notes | |
|---|---|
An agent CLI on PATH |
claude (Claude Code) or elyra. The server also knows a codex provider; this daemon has no adapter for it yet and refuses such a task at claim, saying so |
| The CLI signed in as the daemon's user | Its credentials live in that user's $HOME. Not logged in on every run is this, and nothing else |
| Rust 1.85+ | To build. There are no published binaries yet |
| Git | For checkouts, with whatever credentials that user already has — an SSH agent, a credential helper, a deploy key |
Linux: bwrap (bubblewrap) |
Optional. Without it the sandbox's confined policy falls back to limits and says so in the log. apt install bubblewrap, dnf install bubblewrap |
| macOS: nothing extra | sandbox-exec ships with the system |
| A daemon token | Issued in Félagi: Admin → Runtimes → Connect a machine, or php artisan felagi:daemon-token on the server. Shown once |
The daemon is tested on macOS and Linux. It should build on Windows but has not been run there, and the sandbox has nothing to enforce with.
1. Build it
git clone <daemon-repository-url> felagi-daemon && cd felagi-daemon
cargo build --release
A release build takes a minute or two the first time. The binary is target/release/felagi;
--version should print felagi 0.7.0 or later.
Put it on the path:
sudo install -m 755 target/release/felagi /usr/local/bin/felagi
install rather than cp so the mode is set in the same step, and so a later build replaces it
atomically.
2. Check the machine before configuring anything
felagi providers
elyra /opt/homebrew/bin/elyra
claude_code /Users/kh/.local/bin/claude
A CLI that is installed but not listed is not on the PATH of this shell. That matters more
than it sounds: a service manager starts the daemon with a much shorter PATH than your terminal
has, which is the commonest reason a daemon that worked in the foreground finds no providers
under systemd or launchd. Running as a service deals with it.
3. Configure
felagi setup --server https://felagi.example.com --token fdt_… --name build-box
This writes ~/.felagi/config.json:
{
"server_url": "https://felagi.example.com",
"token": "fdt_…",
"daemon_id": "5f2c…",
"name": "build-box",
"sandbox": "confined"
}
| Key | |
|---|---|
server_url |
Where the browser goes. Trailing slash removed |
token |
The credential. The file is written 0600 because of it |
daemon_id |
This machine's identity, generated once and kept across re-setups, so rotating a token does not make the server think a new machine appeared |
name |
What the runtimes list calls this machine. Defaults to the hostname. Name it after itself — kh-macbook, build-box — because that is what you will read when deciding where work ran |
sandbox |
confined (default), limits, or off. See the sandbox |
Re-running setup keeps the daemon_id and replaces the rest. That is how you rotate a token.
One configuration, one workspace. A token belongs to a workspace, and the file holds one
token. A machine that should serve two workspaces runs two daemons with two HOMEs — the
configuration directory follows $HOME, and there is no flag to point it elsewhere.
4. Start it in the foreground
felagi start
INFO registered workspace=acme runtimes=2 providers=claude_code, elyra sandbox=confined
That line is the whole test. Within a few seconds Admin → Runtimes in Félagi shows the machine, online. If it does not:
felagi status
prints the configuration, the providers found, and whether the server answered.
Leave it running and hand an agent an issue. When the run finishes, stop it with Ctrl-C and install it as a service — Running as a service.
Logging
The daemon logs to stderr, through tracing. FELAGI_LOG sets the level, in RUST_LOG
syntax:
FELAGI_LOG=debug felagi start
FELAGI_LOG=info,felagi::exec=debug felagi start
info is the default and is quiet: one line per registration, one per task start, one per
warning. A run's own output does not go to the log at all — it is streamed to the server and
read on the issue page, which is where it is useful.
Updating
There is no self-update. When the server answers 426 Upgrade Required the daemon says so and
stops, and the response carries the minimum version:
cd felagi-daemon && git pull --ff-only && cargo build --release
sudo install -m 755 target/release/felagi /usr/local/bin/felagi
# then restart the service
The configuration is untouched by an update; daemon_id survives, so the server sees the same
machine come back.
Uninstalling
sudo rm /usr/local/bin/felagi
rm -rf ~/.felagi # configuration, and every task's work directory
Then revoke the token in Admin → Runtimes. Removing the binary does not revoke anything; the token stays valid until you say otherwise, and a copy of it on another machine would still work.
When something is wrong
| Symptom | Meaning | Do |
|---|---|---|
no configuration at …; run felagi setup first |
Never configured, or running as a different user than the one who ran setup |
Run setup as the service user |
token rejected; run felagi setup again (401) |
Revoked, expired or mistyped | Issue a new token in Félagi and re-run setup |
this daemon is too old for the server (426) |
Server's minimum version has moved | Update |
runtime is no longer registered (410) on heartbeat |
The server forgot this machine | Nothing: the daemon registers again on its own |
rate limited; pausing polling (429) |
The server asked for less traffic | Nothing: it waits as long as it was told, then resumes |
no agent CLI found on PATH |
Nothing to run work with | Install a CLI, or fix PATH — especially under a service manager |
provider … is not supported by this daemon |
A Codex agent, or a provider newer than this build | Change the agent's provider, or update |
| Every run ends Not logged in | The CLI is not signed in as the daemon's user | Sign in as that user; claude -p "hello" must work in its shell |
| Runs never claimed, runtime online | A server-side reason | The Félagi guide lists the three usual ones |
| Cloning fails, quickly, naming the repository | No credential for that repository as this user | git clone it by hand as the same user; the daemon has nothing the shell does not |
The daemon never asks for a password. A headless machine that stops for one is a task that hangs
until its lease expires with nothing to explain it, so GIT_TERMINAL_PROMPT=0 is set and there
is no askpass. It fails fast and names the repository instead.