Summary
The README documents a Linux systemd user unit for auto-restarting the dashboard, but for macOS it only says "macOS users can run the same command under a launchd user agent; a full plist is deferred." We should ship a complete, copy-pasteable launchd LaunchAgent example (a generic "starter" plist) plus the launchctl commands, so macOS users get parity with the Linux instructions.
Current Behavior
- README (root) has a working
systemd --user unit for Linux.
- macOS is a one-line placeholder — no plist, no
launchctl commands, no gotchas documented.
Proposed Behavior
Add a macOS launchd section next to the Linux systemd block in README.md (and cross-link from packages/coding-agent/docs/dashboard.md) containing:
- A generic
~/Library/LaunchAgents/com.dreb.dashboard.plist template with placeholders for the absolute paths.
launchctl bootstrap / bootout commands (modern API) to load/unload it.
- The rationale + gotchas learned in practice (see Technical Notes).
Starter plist (validated on macOS, local mode)
<?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.dreb.dashboard</string>
<!-- Invoke node directly on the entry point (from `readlink $(which dreb-dashboard)`)
so it does not depend on `/usr/bin/env node` resolving a PATH launchd lacks. -->
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/node</string>
<string>/ABSOLUTE/PATH/TO/@dreb/dashboard/dist/index.js</string>
<string>--port</string>
<string>5343</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>ThrottleInterval</key>
<integer>10</integer>
<!-- HOME is set automatically for user agents, so ~/.dreb/agent/auth.json
(OAuth creds) is found. PATH lets RPC children spawn bash/git/node. -->
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>StandardOutPath</key>
<string>/Users/YOU/Library/Logs/dreb-dashboard.out.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOU/Library/Logs/dreb-dashboard.err.log</string>
</dict>
</plist>
# load / reload
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.dreb.dashboard.plist
# stop / unload
launchctl bootout gui/$(id -u)/com.dreb.dashboard
# status
launchctl print gui/$(id -u)/com.dreb.dashboard | grep -E 'state|pid'
Acceptance Criteria
Technical Notes / learnings
These are the non-obvious points that made a real setup work — worth capturing in the docs:
- LaunchAgent, not LaunchDaemon. The dashboard must run as the logged-in user: it reads
~/.dreb/agent/sessions + auth.json and spawns dreb --mode rpc children under that user. A root LaunchDaemon would have the wrong HOME/creds.
- Invoke
node directly, not the dreb-dashboard symlink. The bin is a #!/usr/bin/env node script; launchd's minimal environment can fail to resolve node via PATH. Point ProgramArguments[0] at the absolute node binary and [1] at the resolved dist/index.js.
- PATH matters for children. RPC agent children run
bash/git/node; set a sane PATH in EnvironmentVariables (Homebrew + install-prefix bin dirs).
- Credentials: OAuth subscription tokens live in
~/.dreb/agent/auth.json and are found via the auto-set HOME, so no secrets in the plist. Only API-key-via-env users need to add keys to EnvironmentVariables.
KeepAlive + ThrottleInterval gives crash auto-restart without a tight fail-loop. Verified: kill -9 the process and launchd respawns it in a few seconds, HTTP 200 restored.
- Prefer the modern
launchctl bootstrap/bootout gui/$(id -u) API over the deprecated load/unload.
Context
- README placeholder: root
README.md, the line "macOS users can run the same command under a launchd user agent; a full plist is deferred." (right after the Linux systemd example).
- Should mirror the structure/tone of the existing Linux systemd block.
Suggested labels: documentation, dashboard.
Summary
The README documents a Linux systemd user unit for auto-restarting the dashboard, but for macOS it only says "macOS users can run the same command under a launchd user agent; a full plist is deferred." We should ship a complete, copy-pasteable launchd LaunchAgent example (a generic "starter" plist) plus the
launchctlcommands, so macOS users get parity with the Linux instructions.Current Behavior
systemd --userunit for Linux.launchctlcommands, no gotchas documented.Proposed Behavior
Add a macOS launchd section next to the Linux systemd block in
README.md(and cross-link frompackages/coding-agent/docs/dashboard.md) containing:~/Library/LaunchAgents/com.dreb.dashboard.plisttemplate with placeholders for the absolute paths.launchctl bootstrap/bootoutcommands (modern API) to load/unload it.Starter plist (validated on macOS, local mode)
Acceptance Criteria
README.mdmacOS placeholder is replaced with a full LaunchAgent example +launchctlload/unload/status commands.packages/coding-agent/docs/dashboard.mdgains (or links to) the same launchd walkthrough.~/.dreb/agentand spawn RPC children as that user).command -v nodeandreadlink $(command -v dreb-dashboard)), since they vary by install method (Homebrew npm,~/.npm-global, bun global, nvm).~/.dreb/agent/auth.json); users on API-key providers via shell env must add those keys toEnvironmentVariables(LaunchAgents do not source shell profiles).127.0.0.1) and point to the Tailscale--remote/--httpspath for phone access rather than exposing the port.Technical Notes / learnings
These are the non-obvious points that made a real setup work — worth capturing in the docs:
~/.dreb/agent/sessions+auth.jsonand spawnsdreb --mode rpcchildren under that user. A root LaunchDaemon would have the wrongHOME/creds.nodedirectly, not thedreb-dashboardsymlink. The bin is a#!/usr/bin/env nodescript; launchd's minimal environment can fail to resolvenodevia PATH. PointProgramArguments[0]at the absolute node binary and[1]at the resolveddist/index.js.bash/git/node; set a sanePATHinEnvironmentVariables(Homebrew + install-prefix bin dirs).~/.dreb/agent/auth.jsonand are found via the auto-setHOME, so no secrets in the plist. Only API-key-via-env users need to add keys toEnvironmentVariables.KeepAlive+ThrottleIntervalgives crash auto-restart without a tight fail-loop. Verified:kill -9the process and launchd respawns it in a few seconds, HTTP 200 restored.launchctl bootstrap/bootout gui/$(id -u)API over the deprecatedload/unload.Context
README.md, the line "macOS users can run the same command under a launchd user agent; a full plist is deferred." (right after the Linux systemd example).Suggested labels:
documentation,dashboard.