Platform teams moving OpenClaw onto a Canada remote Mac M4 often copy the desktop playbook: open Screen Sharing, run full openclaw onboard, hope the Gateway survives after SSH drops. CI and batch workloads need a different contract—a headless install path using official install-cli.sh with --no-onboard, pre-seeded config, and launchd health probes instead of wizard prompts. This post answers one question only: how to land reproducible headless OpenClaw CI on a cloud Mac / Mac mini cloud build seat. It does not re-litigate SSH tunnel vs direct Gateway access (OpenClaw Canada M4: SSH gateway, 18789 token & launchd) or the interactive onboard log playbook (Remote Mac install, onboard & LaunchDaemon 24/7). If the same Mac mini hosting seat also runs a GitHub Actions runner, split Unix users and launchd labels per self-hosted macOS runners on cloud Mac so Node versions and port 18789 never fight.
For headless CI, anchor on three ideas:
-
install-cli.sh --no-onboardskips the wizardConfig dir and tokens come from your runbook—ideal for Ansible or GHA workflows.
-
Probes must cover launchd, 18789, and sharp
A passing
curlis not enough; plist absolute paths and native modules matter. -
Canada M4 dedicated seats for 24/7
24GB unified memory and 512GB+ SSD; queue Gateway work separately from CI jobs.
1. When you must use headless --no-onboard instead of interactive onboard
Interactive openclaw onboard shines on a Mac with a real GUI session where an operator can approve TCC prompts (Accessibility, Automation, Screen Recording). That is the right first-run experience on a developer laptop. It is the wrong default when the target is a cloud Mac CI lane reached only by SSH or a self-hosted runner, and when configuration is already generated by internal templates. Continuing to invoke the wizard blocks pipelines and creates snowflake hosts that cannot be rebuilt from Git.
The headless contract looks like this:
- Pin Node LTS and global
openclawCLI semver viainstall-cli.sh. - Pass
--no-onboardand sync the config directory (paths per upstream docs, commonly under~/.openclaw) from secrets management. - Schedule a one-time Screen Sharing window only if your agents need browser automation that still requires TCC; after that, operate purely through launchd.
Compared with our “remote Mac stability” note, this article delivers a versioned CI runbook and probe scripts—not a desktop operator manual. If your team still types answers into onboard on every new seat, you have not yet reached headless maturity.
2. Headless install-cli.sh vs full onboard: how to choose
| Dimension |
install-cli.sh --no-onboard
CI / batch · repeatable
|
Full openclaw onboard
Desktop · first TCC
|
|---|---|---|
| Best for | GHA, cron, homogeneous fleet scale-out | Single-seat VNC setup, menu bar app |
| Config source | Git template + CI secrets | Wizard writes step-by-step |
| Gateway 18789 | Runbook pins 127.0.0.1 + bearer token | Wizard issues bearer token |
| launchd | Script or post-install install-daemon | Optional --install-daemon |
| Typical failures | PATH drift, sharp load, config semver skew | Missing TCC, port already bound |
| Sweet spot | Mac mini hosting 24/7 agent pools | Developer laptop sidecar debugging |
When provisioning a fresh Mac mini cloud seat from a provider, run your headless smoke pipeline first. Teams that “onboard once by hand” often discover weeks later they cannot disaster-recover the Gateway in under an hour.
3. Headless provisioning runbook: install-cli.sh and config injection
The examples below assume a dedicated system user openclaw-ci, isolated from the VNC admin account. On a Canada M4 cloud Mac, pin Node to LTS (22.x is a reasonable 2026 baseline) and keep it separate from any runner user’s nvm shims—launchd jobs do not load interactive shell profiles.
# SSH as openclaw-ci on the cloud Mac export OPENCLAW_CONFIG_DIR="$HOME/.openclaw" curl -fsSL https://example.openclaw.dev/install-cli.sh | bash -s -- --no-onboard # Restore config from CI secrets — never commit tokens to Git install -d -m 700 "$OPENCLAW_CONFIG_DIR" echo "$OPENCLAW_CONFIG_JSON" > "$OPENCLAW_CONFIG_DIR/config.json" # Install Gateway launchd service when supported openclaw gateway install-daemon openclaw doctor --non-interactive
Operational notes that separate hobby installs from production cloud Mac lanes:
- Idempotency: Your workflow must tolerate re-runs. A good script no-ops or converges version when already installed.
- Semver lock: Record
openclaw --versionand config schema version in the runbook; upgrades go through a change window with rollback steps. - Disk layout: Keep npm/pnpm caches on a path you can wipe independently from Derived Data if the same host also builds iOS artifacts.
- Checksum: Pin the install script digest in production; naked
curl | bashwithout verification is an supply-chain incident waiting to happen.
xcodebuild; openclaw-ci owns the Gateway. Never share one launchd job label or one global node_modules/.sharp tree across both.
4. launchd health checks: process, port, and log triangle
In headless mode, “Gateway seems up” often means someone ran curl once from an SSH session with a full PATH. Production probes should validate launchd state, listen address, and log keywords together. Run every five minutes via cron or a scheduled GHA workflow:
#!/bin/bash set -euo pipefail LABEL="ai.openclaw.gateway" launchctl print "gui/$(id -u)/$LABEL" | grep -q 'state = running' lsof -nP -iTCP:18789 -sTCP:LISTEN | grep -q openclaw curl -sf -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \ http://127.0.0.1:18789/health | grep -q '"ok":true' tail -n 50 ~/Library/Logs/openclaw/gateway.log | grep -Ei 'sharp|EADDRINUSE|401' && exit 1 || true
The plist must invoke openclaw with an absolute path and set explicit EnvironmentVariables, including PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin. launchd does not read your interactive ~/.zprofile. That mismatch is the top reason commands work over SSH but the daemon exits immediately on a rented cloud Mac.
Extend probes with duration metrics: track p95 latency of /health and alert when cold starts exceed your workflow timeout budget. A Gateway that answers in four seconds interactively but thirty seconds under launchd may still fail CI jobs configured with tight retries.
5. Probe result matrix: green, yellow, and red responses
| Level | Signals | Recommended action |
|---|---|---|
| Green | launchd running + 18789 LISTEN + /health 200 | Rotate gateway.log older than 7 days only |
| Yellow | Slow /health or intermittent 401; no sharp errors in logs | Verify token rotation; run openclaw doctor; cap concurrent agent jobs |
| Red | launchd exit loop; EADDRINUSE; sharp load failure | Stop job queue; bootout + rebuild plist; follow sharp section below |
Treat yellow lasting more than twenty-four hours as a release blocker. Headless CI assumes predictable Gateway behavior; intermittent auth or latency failures amplify into whole-batch agent timeouts that are expensive to debug without VNC.
6. sharp native module troubleshooting on Apple Silicon cloud Macs
OpenClaw’s dependency graph includes sharp (libvips bindings). On M4 arm64 hosts, mismatched Node major versions or mixed install users produce errors like Cannot find module '../build/Release/sharp.node' or architecture mismatch at runtime. Headless CI cannot discover this on the first failed job—bake sharp validation into golden images or post-install hooks.
6.1 Common failure modes and fixes
- User mismatch: root installed global CLI while
openclaw-ciruns the daemon—reinstall sharp or the CLI as the service user. - Node upgrade without rebuild: after bumping Node, run
npm rebuild sharpor reinstall the openclaw CLI package. - Rosetta mix: plist and CLI must both be arm64;
file $(which node)should report arm64. - Offline cache: on bandwidth-constrained Mac mini cloud hosts, prefetch sharp binaries so CI jobs do not hit GitHub releases every run.
- Multiple Node managers: avoid Homebrew Node for the daemon while interactive shells use
nvm—pick one story and encode it in the plist.
node -p "process.arch + ' ' + process.version" npm ls sharp --global 2>/dev/null || true npm rebuild sharp --foreground-scripts openclaw doctor 2>&1 | tee /tmp/openclaw-doctor.log grep -i sharp /tmp/openclaw-doctor.log && exit 1 || echo "sharp OK"
If doctor still reports sharp, align Node and CLI install channels from the same install-cli.sh artifact before chasing application-level bugs. Mixing Homebrew Node with a npm-global CLI without plist PATH fixes is the sharp edge we see most often on Mac mini hosting tickets.
7. Gateway 18789 boundaries and token rotation in CI
Headless pipelines should call the local Gateway at 127.0.0.1:18789 with a bearer token—never expose the port on a public interface. Store tokens in CI secrets (for example OPENCLAW_GATEWAY_TOKEN). Rotation flow: write the new token into config, reload the daemon, validate probes green, then revoke the old secret. Loopback access keeps latency minimal when runner and Gateway share one cloud Mac; cross-host calls belong in the SSH gateway note linked above.
Workflows should use explicit timeouts and limited retries. Cold start can take ten to thirty seconds after reboot; a failed probe should trigger launchctl kickstart once before any destructive reinstall. Document that behavior so on-call engineers do not wipe working config during transient boot storms after macOS patches.
8. Security baseline for headless OpenClaw on hosted Mac seats
- Dedicated user:
openclaw-ciwithout admin rights or VNC login. - Secrets: config and tokens only from your vault; enable FileVault on the volume.
- Network: inbound SSH or Tailscale only; do not broadcast 18789 on LAN.
- Supply chain: verify install script checksums; block unaudited pipe-to-bash in production.
- Audit: retain gateway.log fourteen days; ship 401 and sharp keywords to your log stack.
- Blast radius: agent tools profile should follow least privilege; fork PRs must not reach production Gateway hosts.
Headless automation increases velocity; it also removes the human pause where someone might notice a suspicious install URL. Treat the install script URL and checksum with the same rigor as production TLS certificates.
9. Wiring headless OpenClaw into GHA or internal CI
Once Gateway probes are green, expose OpenClaw to pipelines through guarded steps:
- Export
OPENCLAW_GATEWAY_TOKENfrom GitHub Environments with required reviewers for production. - Run agent jobs on
runs-on: [self-hosted, macos-m4-canada, openclaw]labels distinct from signing or archive jobs. - Preflight with the same shell probe used by cron; fail fast before expensive LLM or browser steps.
- Capture
openclaw doctoroutput as a workflow artifact on failure for async review.
Memory planning: on a 24GB Mac mini cloud seat, pause OpenClaw agent batches when unified memory pressure exceeds eighty percent if the same host must finish an xcodebuild archive the same night. Queue depth alerts prevent operators from blaming “GitHub being slow” when the host is simply oversubscribed.
10. First-week checklist on a Canada M4 dedicated seat
- Select a Mac mini hosting plan (24GB RAM and 512GB SSD minimum for combined CI + Gateway).
- Create
openclaw-ciand passinstall-cli.sh --no-onboardsmoke tests. - Inject config and token; ensure
openclaw doctor --non-interactiveis clean. - Install launchd and deploy green/yellow/red probes with paging.
- Prevalidate
sharp; lock Node and CLI versions in the runbook. - If a GHA runner shares the host, verify separate users and no port conflicts.
- Document rebuild: a new cloud Mac seat should reach identical Gateway behavior within thirty minutes.
11. FAQ
Do I still need VNC after --no-onboard?
If agents require browser automation or TCC permissions, schedule a one-time graphical session. Pure CLI or API Gateway workloads can run without VNC indefinitely once launchd is stable.
install-cli.sh vs full install.sh?
Use install-cli.sh when CI needs CLI plus Gateway only. Full installers that ship menu bar apps are poor fits for repeated headless runner deployments.
Probe returns 401 but the process is running?
Usually token rotation drift or workflows still sending an old secret. Align config on disk with the Authorization header; check proxies that inject stale tokens.
sharp fails under launchd but works over SSH?
Almost always PATH or user environment differences. Compare launchctl print environment blocks with interactive env output side by side.
Can I run OpenClaw Gateway in Docker on macOS?
Docker on Mac cannot replace native TCC and GUI automation requirements. Run Gateway under native launchd; containers are fine for peripheral tools only.
How do I schedule OpenClaw alongside GitHub Actions on one host?
Stagger agent batches away from archive peaks; pause agents above eighty percent memory pressure. See label and concurrency guidance in the self-hosted runner article.
Is a Hashvps Canada node a good fit for headless OpenClaw?
Yes when you need dedicated IPv4, bare-metal M4, and persistent SSH. Confirm disk tier fits npm caches and rotated gateway logs before committing.
What is the standard CLI upgrade procedure?
Maintenance window: launchctl bootout, converge version via install-cli, npm rebuild sharp, doctor, green probes, then restore traffic.
Headless OpenClaw needs a stable Mac mini cloud foundation
install-cli.sh --no-onboard solves repeatable deploys; long-term stability depends on the cloud Mac underneath. M4 unified memory cuts tail latency for parallel agents; native macOS launchd and OpenSSH keep probes and CI on the same machine; sub-five-watt idle draw suits Mac mini hosting around the clock; Gatekeeper and FileVault lock Gateway tokens to auditable egress—a better production agent pool than weekly-reset ephemeral VMs.
If you are moving OpenClaw headless CI onto a Canada dedicated seat, compare Mac mini cloud plans and ship your first pipeline this week.