Run agentboard as a persistent launchd user agent that starts at login and restarts on crash. Parallel to systemd/ for Linux.
- macOS
bunin PATH (brew install oven-sh/bun/bun)tmuxin PATH (brew install tmux)- Repository cloned locally (service runs
bun run startfrom the repo directory)
./launchd/install.shThe install script will:
- Detect
bunandtmuxpaths - Generate a wrapper script and a log-rotate script in
~/.agentboard/bin/ - Generate two plists in
~/Library/LaunchAgents/ - Load them via
launchctl
Installs two agents:
com.agentboard— supervises agentboard.KeepAliverespawns on crash or non-zero exit,ThrottleInterval: 10prevents tight restart loops.com.agentboard.logrotate— hourly. Rotatesagentboard.log,launchd.out.log, andlaunchd.err.logunder~/.agentboard/at 50MB each using a copytruncate pattern (preserves pino's open file descriptor), keeps 5 gzipped archives per file.
After install, agentboard listens on http://localhost:4040.
# Status
launchctl list | grep agentboard
# Tail logs (structured JSON, same as in systemd setups)
tail -f ~/.agentboard/agentboard.log
# Launchd stdout/stderr (captures startup errors)
tail ~/.agentboard/launchd.{out,err}.log
# Force restart
launchctl kickstart -k gui/$(id -u)/com.agentboard
# Stop (e.g. before running `bun run dev` against port 4040)
launchctl unload ~/Library/LaunchAgents/com.agentboard.plist
# Re-enable
launchctl load -w ~/Library/LaunchAgents/com.agentboard.plist
# Manual log rotation (no-op below 50MB)
~/.agentboard/bin/agentboard-log-rotate.shfor label in com.agentboard com.agentboard.logrotate; do
launchctl unload ~/Library/LaunchAgents/$label.plist 2>/dev/null || true
rm -f ~/Library/LaunchAgents/$label.plist
done
rm -rf ~/.agentboard/bin
# To also remove data: rm -rf ~/.agentboardAgentboard tracks Hibernating sessions in ~/.agentboard/agentboard.db, keeps them dormant across restarts, and lets you wake them manually from the UI. But when the tmux server crashes mid-flight, agentboard's process keeps running with stale handles — attached PTYs are dead and the base tmux session does not come back until agentboard restarts. Until then, the UI stays broken.
A small 30-second polling agent that kickstarts agentboard whenever the base session disappears solves this. Opt-in because it's only needed if you've actually seen tmux crash on your machine.
Create the script:
cat > ~/.agentboard/bin/tmux-agentboard-watchdog.sh << 'EOF'
#!/bin/bash
export PATH="$(dirname "$(command -v tmux)"):/usr/local/bin:/usr/bin:/bin"
SESSION="${TMUX_SESSION:-agentboard}"
tmux has-session -t "$SESSION" 2>/dev/null || \
launchctl kickstart -k "gui/$(id -u)/com.agentboard"
EOF
chmod +x ~/.agentboard/bin/tmux-agentboard-watchdog.shCreate the plist:
cat > ~/Library/LaunchAgents/com.agentboard.tmux-watchdog.plist << EOF
<?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>com.agentboard.tmux-watchdog</string>
<key>ProgramArguments</key>
<array><string>$HOME/.agentboard/bin/tmux-agentboard-watchdog.sh</string></array>
<key>StartInterval</key><integer>30</integer>
<key>RunAtLoad</key><true/>
<key>StandardOutPath</key><string>/tmp/agentboard-tmux-watchdog.log</string>
<key>StandardErrorPath</key><string>/tmp/agentboard-tmux-watchdog.log</string>
</dict>
</plist>
EOF
launchctl load -w ~/Library/LaunchAgents/com.agentboard.tmux-watchdog.plistThe watchdog checks tmux has-session -t agentboard every 30s. If the session is gone (server crashed, or session killed), it runs launchctl kickstart -k gui/$(id -u)/com.agentboard which triggers agentboard's startup path. ensureSession() recreates the base session; Hibernating sessions stay dormant and can be woken manually from the UI.
Note: if you tmux kill-session -t agentboard while agentboard is loaded, the watchdog will restore it within 30s. To stop cleanly, launchctl unload ~/Library/LaunchAgents/com.agentboard.plist first.
- The plist sets
LANG=en_US.UTF-8. LaunchAgents start with a bare environment; without this, tmux renders non-ASCII characters as?or stripped bytes. - The wrapper script
cds into the repo directory beforebun run start, matching the Linux systemd setup. - Override the log path via the
LOG_FILEenv var (respected by agentboard and the rotate script). - Override the tmux session name via
TMUX_SESSION(respected by agentboard and the watchdog).