Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Start here
Concepts
Release notes
What's new
Elyra
Running as a service

Running as a service

The daemon is a foreground process by design: no daemonising, no pid file, no log rotation of its own. A service manager does those things better and already exists on every machine this will run on. Two are covered here — systemd on Linux and launchd on macOS — and the same three facts apply to any other.

Get it working in the foreground first — Installing. A service that has never been seen to succeed by hand is one that cannot be debugged.


The three things every service manager gets wrong by default

PATH

A service starts with a short PATH. Your terminal has ~/.local/bin, Homebrew, ~/.cargo/bin and whatever your shell profile added; the service has /usr/bin:/bin. The daemon finds agent CLIs on PATH and nowhere else — so a daemon that registered two providers in your terminal registers none as a service, and the log says no agent CLI found on PATH.

Set PATH explicitly in the unit or plist, to include wherever claude and elyra actually are. which claude in your terminal tells you.

HOME, and which user

The CLI's sign-in, the SSH agent, the git credential helper and the daemon's own configuration all live in $HOME. Run the service as the user who signed in to the CLI and ran felagi setup, with that user's HOME. A service running as root or nobody has none of it, and every run fails with Not logged in or a clone that cannot authenticate.

Stopping

The daemon handles SIGTERM and SIGINT the same way: it stops claiming, each running task kills its CLI and reports itself back to the server as retryable, and the process exits once those reports have landed — up to thirty seconds. Give the service manager at least forty seconds before it sends SIGKILL. Killed early, the tasks it held sit as running in Félagi until the sweeper notices five minutes later; stopped properly, they are requeued at once.


systemd (Linux)

A user unit, so it runs as you and finds your HOME. /etc/systemd/user/ for every user or ~/.config/systemd/user/ for one.

# ~/.config/systemd/user/felagi.service
[Unit]
Description=Félagi agent daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/felagi start
Restart=on-failure
RestartSec=5

# The daemon hands its tasks back on SIGTERM and needs up to 30 s to do it.
KillSignal=SIGTERM
TimeoutStopSec=40

# The two things systemd's default environment does not have.
Environment=FELAGI_LOG=info
Environment=PATH=%h/.local/bin:%h/.cargo/bin:/usr/local/bin:/usr/bin:/bin

[Install]
WantedBy=default.target

%h is the user's home. Add the directory which claude printed if it is not one of those.

systemctl --user daemon-reload
systemctl --user enable --now felagi
systemctl --user status felagi
journalctl --user -u felagi -f

A user unit stops when the user logs out unless lingering is on:

sudo loginctl enable-linger $USER

Without it, the daemon runs while you are signed in and vanishes when you are not — which on a build box is most of the time, and the runtimes list will show it flickering offline.

Confinement needs bubblewrap. apt install bubblewrap or dnf install bubblewrap. Without it the log says so at start and the sandbox runs as limits: resource caps but no write confinement. The policy in force is reported to the server and shown in the runtimes list, so an unconfined machine is visible without logging in to it.

launchd (macOS)

A user agent, in ~/Library/LaunchAgents/, so it runs as you.

<!-- ~/Library/LaunchAgents/no.felagi.daemon.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>no.felagi.daemon</string>

  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/bin/felagi</string>
    <string>start</string>
  </array>

  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>

  <!-- Up to 30 s to hand tasks back on SIGTERM. -->
  <key>ExitTimeOut</key>
  <integer>40</integer>

  <key>EnvironmentVariables</key>
  <dict>
    <key>FELAGI_LOG</key>
    <string>info</string>
    <key>PATH</key>
    <string>/Users/kh/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
  </dict>

  <key>StandardOutPath</key>
  <string>/Users/kh/Library/Logs/felagi.log</string>
  <key>StandardErrorPath</key>
  <string>/Users/kh/Library/Logs/felagi.log</string>
</dict>
</plist>

Replace /Users/kh with your home; launchd does not expand ~. Put the directory which claude printed in PATH.

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/no.felagi.daemon.plist
launchctl print gui/$(id -u)/no.felagi.daemon | head -20
tail -f ~/Library/Logs/felagi.log

To stop and remove:

launchctl bootout gui/$(id -u)/no.felagi.daemon

A user agent runs while that user is logged in, including a locked screen, and not otherwise. A Mac meant to serve agents around the clock stays logged in — or the daemon runs as a system daemon in /Library/LaunchDaemons/ with UserName set, which then needs that user's HOME in EnvironmentVariables too.

Sleep stops runs. A laptop lid closed mid-run stops the CLI; the daemon's heartbeat stops with it, the server marks the runtime offline within 45 seconds, and the task is requeued when its lease expires. Nothing is lost, and nothing hangs — but a machine that sleeps is not a machine to rely on for long runs. caffeinate or Prevent automatic sleeping in Energy settings, if it is meant to be one.


Checking that it is really running

Three places, and they should agree:

Says
systemctl --user status felagi / launchctl print … The process is up
The log registered … providers=… — with every provider you expected. Fewer means PATH
Admin → Runtimes in Félagi The machine, online, with its sandbox policy

Online is computed from heartbeats, not stored: a runtime that shows online has been heard from in the last 45 seconds. A crashed daemon cannot leave one looking alive.