Skip to content

Service and logs

The daemon runs as a background service on each machine. This page covers how it’s installed on each platform, where it keeps its state and logs, who can connect to it, and its flags.

arugulad install copies the binary to ~/.local/bin and installs the service. Run it again to upgrade; programs in your panes keep running during the upgrade. Flags after -- go to the daemon on every start, and later installs and updates keep them (--reset-args drops them):

Terminal window
arugulad install -- --owner you@example.com

Each platform runs the daemon with its own service manager.

The desktop app’s daemon. If you installed only the desktop app, it runs the daemon from inside itself, as a Login Item: see The Mac app’s daemon. Its log is ~/Library/Logs/arugulad.log.

A launchd agent. arugulad install (which the install script and Homebrew use) writes ~/Library/LaunchAgents/arugulad.plist, which starts the daemon at login and after a crash.

  • Logs: ~/Library/Logs/arugulad.log
  • Restart: launchctl kickstart -k gui/$UID/arugulad
  • Stop: launchctl bootout gui/$UID/arugulad

macOS has no systemd, so each pane’s small helper process keeps its terminal while the daemon is gone (the plist sets --keep-panes): a restart, an update or a crash leaves the programs running. Stopping the daemon for good ends them a minute later, if no daemon has come back. Panes run your login shell from the user database.

A Mac with no GUI login (one you reach only over ssh, where that user hasn’t logged in to the desktop since it booted): arugulad install puts the same agent in the background session. It keeps running after you log out, but after a reboot it doesn’t start until you log in to the desktop or run arugulad install again (arugula --ssh does that for you when the daemon isn’t running), and the install says so.

From boot: arugulad install --system installs a LaunchDaemon, /Library/LaunchDaemons/arugulad.$USER.plist, that runs the daemon as you from boot, with nobody logged in. Run it as yourself, not as root: it runs sudo for the two steps that need it. It replaces the agent; run arugulad uninstall first to go back. sudo launchctl kickstart -k system/arugulad.$USER restarts it.

arugulad uninstall stops and removes whichever service arugulad install set up; the binaries and your state stay (Uninstalling). arugula status says which service runs the daemon, its version, binary and log, and whether it’s joined to Arugula control.

The daemon keeps layout, output, checkpoints and settings in its state directory, private to you (the folder is 0700, its files 0600):

  • $ARUGULA_STATE_DIR if it’s set;
  • else $XDG_STATE_HOME/arugula;
  • else ~/.local/state/arugula;
  • on Windows, %LOCALAPPDATA%\arugula\state.

--state-dir moves it.

On this machine, only you can connect: the CLI through a Unix socket in your private state directory, and anything on the TCP port only if it shows the daemon’s local token (local-token in the state directory, made at the first start). Loopback is shared by every account and program on the machine, so being on it isn’t enough.

  • Your browser gets the token as a cookie from a sign-in link: arugula web opens http://127.0.0.1:7681 through it (--print prints the link, to open by hand or through an ssh -L forward). Once per browser; it stays signed in until the token changes. The desktop app signs its own window in.
  • Programs send it as Authorization: Bearer {token} (arugula --host http://127.0.0.1:7681 does that for you). MCP clients use arugula mcp or an arugula mcp token.
  • A new token signs every browser and program out: delete local-token and restart the daemon.

Over your tailnet, the daemon asks Tailscale who each caller is and lets in only the login that owns the machine (--owner names another). Behind tailscale serve, the identity it adds is believed only from Tailscale’s own connection. Tagged nodes, Funnel and the internet never get in.

Through Arugula control, only your approved devices get in, over end-to-end encrypted connections.

The daemon updates itself when you ask (Update now, or arugulad update), and keeps your flags: see Install. If an update fails before the restart, the old daemon carries on and says why in update.log in the state directory.

arugulad --help lists every flag. These are the ones you’re likeliest to want. Pass them with arugulad install -- FLAGS so the service keeps them; on a Mac where the desktop app runs the daemon, see The Mac app’s daemon.

Flag Environment variable What it does
--listen ADDR ARUGULA_LISTEN where the page and API listen (default 127.0.0.1:7681; keep it on loopback)
--owner LOGIN ARUGULA_OWNER the Tailscale login allowed in (default: the machine’s owner)
--name NAME ARUGULA_NAME this machine’s name in host lists
--state-dir DIR ARUGULA_STATE_DIR where state lives
--shell "CMD ARGS" the command new panes run (default $SHELL -l)
--no-shell-integration start shells without prompt and command marks
--no-manager-env don’t copy systemd’s user environment into new panes
--keep-panes ARUGULA_KEEP_PANES without systemd: keep programs running across restarts
--no-claude-ide ARUGULA_NO_CLAUDE_IDE don’t be Claude Code’s IDE (no diff cards)
--no-update-check ARUGULA_NO_UPDATE_CHECK don’t check for new releases
--control URL ARUGULA_CONTROL the Arugula control that Getting started joins (default https://control.arugula.io)
--direct-url URL ARUGULA_DIRECT_URL an address devices can reach this machine at directly
--public-host NAME extra host names to accept
--allow-origin ORIGIN other origins whose pages may use this daemon
--block-listen, --block-domain, … ARUGULA_BLOCK_LISTEN, … browser blocks on ports
--code-server PATH, --editor-idle SECONDS ARUGULA_CODE_SERVER, ARUGULA_EDITOR_IDLE editor blocks
--peer URL, --token FILE, --sync ARUGULA_PEER, ARUGULA_TOKEN_FILE a box that can only dial out