Installing Maxy Code on macOS
End-to-end install for a fresh macOS account on Apple Silicon (M-series). Every command is copy-pasteable and uses auto-yes flags so nothing prompts interactively.
The doc is brand-aware. Examples use the default brand maxy-code; substitute realagent-code (or any other brand under maxy-code/brands/) wherever you want a parallel install. Each brand is fully isolated — its own persist directory, its own LaunchAgent, its own admin UI port, its own CLAUDE_CONFIG_DIR.
Pi install: see pi.md for the Raspberry Pi flow. Other hosts and engineering detail: see index.md and ../deployment.md.
Requirements
- macOS 14 (Sonoma) or newer. The installer refuses to run on 13 and below; you will see
[create-maxy] platform=darwin macos=… — refusing: macOS 14+ required. - Apple Silicon (M1/M2/M3/M4). Intel Macs are not part of the supported matrix — the installer pins
node@22from Homebrew's Apple Silicon cellar (/opt/homebrew) and other paths assume that prefix. - Admin (sudo) account. The installer asks for your password once when it sets the system hostname via
scutil; everything else runs unprivileged. - A working internet connection — Homebrew, npm, and Cloudflare endpoints are all reached during install.
1. Install Node 22 via Homebrew
# Homebrew (skip if already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Node 22 — pinned formula
brew install node@22
brew link --overwrite --force node@22
# Verify (must be 22.6 or newer)
node --version
Node from the system PATH must resolve to /opt/homebrew/opt/node@22/bin/node. If which node points anywhere else, fix the PATH before continuing — the installer reads node from PATH and a 20.x binary will trip the engines check.
2. Run the installer
The default brand is maxy-code. Run from any directory; the installer creates and writes everything under $HOME/.maxy-code.
npx -y @rubytech/create-maxy-code@latest
That command:
- creates the persist directory
$HOME/.maxy-code/(logs, config, plugin state, the.claude/config tree, browser profile); - exports
CLAUDE_CONFIG_DIR=$HOME/.maxy-code/.claudefor every Claude Code invocation it spawns (default~/.claudeis the wrong tree on a multi-brand machine); - builds the platform payload bundled in the npm tarball;
- writes a launchd LaunchAgent at
~/Library/LaunchAgents/com.rubytech.maxy-code.plistand loads it withlaunchctl bootstrap gui/$UID; - prints the admin UI URL when the supervisor reports the server is listening.
The full install log lands at $HOME/.maxy-code/logs/create-maxy-<timestamp>.log. Every phase line is prefixed [create-maxy] phase=… brand=… platform=darwin — that's the canonical signal if you want to attach an install log to a support request.
Optional: --hostname
By default the installer leaves your existing macOS hostname alone and serves the admin UI at http://<your-existing-LocalHostName>.local:<port>. If you want a dedicated name on the LAN, pass --hostname:
npx -y @rubytech/create-maxy-code@latest --hostname maxy
That triggers three sudo scutil --set calls — HostName, LocalHostName, ComputerName — and the admin UI then resolves at http://maxy.local:<port> from any device on the same Bonjour/mDNS network. The flag is the only path that mutates system hostname state; omitting it preserves whatever you had.
Installing a second brand
To run, for example, realagent-code alongside the default install, repeat step 2 with that brand's package:
npx -y @rubytech/create-realagent-code@latest
The persist directory becomes $HOME/.realagent-code, the LaunchAgent becomes com.rubytech.realagent-code, and the admin URL switches to http://realagent-code.local:<port>. Every brand has its own isolated tree — there is no shared state, and CLAUDE_CONFIG_DIR is always $HOME/.<brand>/.claude for that brand, never the default ~/.claude.
3. Confirm the LaunchAgent is up
launchctl print gui/$(id -u)/com.rubytech.maxy-code | head -20
You should see state = running. If the state is not running or the command fails, inspect the plist and the supervised stdout/stderr files referenced inside it:
cat ~/Library/LaunchAgents/com.rubytech.maxy-code.plist
The plist points at the wrapper script the installer wrote and at log files under $HOME/.maxy-code/logs/. launchctl bootstrap's exit code is recorded in the install log as [create-maxy] launchd-plist=… loaded=true|false.
4. Open the admin UI
The install log's final block prints the URL. For the default brand on a default install:
================================================================
Open in your browser: http://<hostname>.local:<port>
================================================================
Open that URL in any browser. The admin UI loads, the operator account is provisioned on first visit, and the platform's chat surface is ready.
5. Verify reboot persistence
Reboot the Mac. After login, the LaunchAgent reattaches automatically because the plist sets RunAtLoad=true and KeepAlive=true. Re-open the admin URL — it should respond within a few seconds without you doing anything.
If the admin UI does not respond after reboot:
- Re-check
launchctl print gui/$(id -u)/com.rubytech.maxy-codeforstate = running. - Tail the supervised log under
$HOME/.maxy-code/logs/. - The wrapper script reloads
$HOME/.maxy-code/.envbefore exec'ing the platform binary; if you edited that file by hand and broke a quoted value, the supervisor will respawn on a fast loop and the URL never becomes reachable.
Uninstall
npx @rubytech/create-maxy-code --uninstall
This unloads the LaunchAgent (launchctl bootout gui/$UID/com.rubytech.maxy-code), removes the plist, removes the Homebrew formula state the installer added, and removes the persist directory $HOME/.maxy-code/. After it completes the brand leaves no trace.
To uninstall a non-default brand, point at its package — for example:
npx @rubytech/create-realagent-code --uninstall
What this install does not do
macOS is the lightweight surface. Compared with the Pi install, the macOS path deliberately skips:
- No cgroup / resource decoupling. Pi installs decouple Claude Code's cgroup from systemd's session scope so a closed VNC viewer cannot reap the long-running agent. macOS uses launchd, which is already per-user and does not have the same cleanup pathology, so the work is unnecessary.
- No VNC. The admin UI is the surface. You drive it from a browser on the same machine or any device on the LAN; there is no display server to bootstrap.
- No
cloudflaredtunnel by default. Pi installs ship a tunnel because the device is typically headless and on a residential network. On a Mac the LAN URL is usually enough; if you want a public URL, installcloudflaredseparately and runcloudflared tunnel loginfrom the terminal. Cloudflare API tokens are never used — only the CLI's interactivetunnel loginflow.
Smoke checklist
The full operator-side fresh-Mac smoke is tracked separately (see .tasks/339-macos-installer-smoke-task-297.md). The headline pass criteria:
- Install on a clean account with no prior Maxy footprint completes and prints an admin URL.
- The admin UI opens at that URL and the chat surface is interactive.
- Reboot — the URL is reachable again after login without any manual action.
- Run
--hostname <name>on a second install path; the URL switches to<name>.local. - Uninstall removes the LaunchAgent, the plist, and the persist directory.
If any step fails, attach $HOME/.<brand>/logs/create-maxy-<timestamp>.log to the report.