#18438: macOS: add in-app CLI + gateway install with reset support
docs
app: macos
scripts
size: L
Cluster:
Gateway and macOS Improvements
## Summary
- **Problem**: macOS onboarding required users to manually install the CLI and start the gateway via terminal commands, creating a poor first-run experience and frequent startup failures.
- **Why it matters**: First-time users faced technical barriers (terminal commands, PATH setup, launchd management) that prevented them from getting started quickly.
- **What changed**: Added in-app CLI installer + gateway manager with visual feedback, automatic startup, and a reset button for troubleshooting.
- **What did NOT change (scope boundary)**: Web provider, other platform onboarding flows, gateway runtime behavior, or configuration options.
## Change Type (select all)
- [x] Feature
- [x] Bug fix (gateway startup reliability)
- [ ] Refactor
- [x] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [x] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [x] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Related to general macOS app stability improvements
## User-visible / Behavior Changes
- **New Install page** (2nd page in onboarding wizard):
- "Install OpenClaw CLI" button installs npm package to `~/Library/pnpm`
- "Start Gateway" toggle installs + starts launchd service (port 18789, Node runtime)
- "Troubleshoot & Reset" section with reset button that clears CLI + gateway + device auth + onboarding state
- **restart-mac.sh gains flags**: `--reset-onboarding` (clear wizard state only), `--full-reset` (clear wizard + reinstall CLI + restart gateway)
- **Gateway startup reliability**: Fixed polling loop that blocked UI counter updates due to @MainActor contention
- **Reinstall behavior**: Toggling gateway off then on now stops existing gateway and reinstalls with latest binary
- **Calendar versioning**: Gateway compatibility now checks year match (2026.x.x compatible with 2026.y.y) instead of semver rules
- **Device auth tokens**: Cleared during manual "Reset Installation" (stored in `~/Library/Application Support/OpenClaw/identity/device-auth.json`, outside `~/.openclaw/`)
- **Navigation**: Next/Back/page dots disabled while install is in progress
## Security Impact (required)
- **New permissions/capabilities?** No (existing npm/node/launchd capabilities only)
- **Secrets/tokens handling changed?** Yes
- **New/changed network calls?** No (only npm install, existing gateway behavior)
- **Command/tool execution surface changed?** Yes
- **Data access scope changed?** No
**Risk + mitigation:**
- Device auth tokens cleared during manual reset to avoid stale credential errors → low risk (intentional operator action via reset button, tokens are regenerated on next login)
- Reset button clears device auth + gateway + CLI in one action → intentional operator action, warns user with confirmation dialog before proceeding
## Repro + Verification
### Environment
- **OS**: macOS 14+ (Sonoma)
- **Runtime**: Node 22+ (via pnpm global install)
- **Model/provider**: N/A (onboarding flow, no model calls yet)
- **Integration/channel**: N/A
- **Relevant config**: Fresh install (no prior `~/.openclaw` or `~/Library/pnpm/openclaw`)
### Steps (Before - broken flow)
1. Download OpenClaw.app, open it
2. See "Install OpenClaw" page with terminal instructions
3. Copy-paste `curl ... | sh` into Terminal, wait for install
4. Return to app, click "Next"
5. Gateway fails to start (missing PATH, wrong runtime, stale disable marker, etc.)
6. User stuck at "Gateway Starting..." indefinitely
### Steps (After - fixed flow)
1. Download OpenClaw.app, open it
2. Click "Install OpenClaw CLI" button on Install page → installs to `~/Library/pnpm`
3. Toggle "Start Gateway" on → installs launchd service, shows startup counter
4. Gateway starts within 15-30s (fresh) or 5-10s (subsequent), counter updates every second
5. "This Mac" auto-selected and Next button enabled
6. If startup fails: click "Reset & Try Again" button → clears everything, retry install
### Expected
- In-app install completes without terminal
- Gateway starts reliably within 30s
- Startup progress visible with live counter
- Reset button clears all state and allows retry
### Actual
✅ All expected behavior verified
## Evidence
- [x] Passing tests (3 new tests added):
- `GatewayEnvironmentTests.calendarVersioningCompatibilitySameYear` (2026.x.x compat)
- `GatewayProcessManagerTests.statusIsReadyForRunningAndAttached` (all 5 Status enum cases)
- `OnboardingViewSmokeTests.installPageIsSecondInPageOrder` (page order validation)
- [x] All existing tests passing (GatewayEnvironmentTests 5/5, GatewayProcessManagerTests 1/1, OnboardingViewSmokeTests 5/5)
- [x] Build verified: `Build of product 'OpenClaw' complete!`
- [x] Manual verification: Fresh install → CLI install button → gateway toggle → startup counter → "This Mac" auto-select → reset button
## Human Verification (required)
**Verified scenarios:**
- Fresh install flow (no prior `~/.openclaw` or CLI)
- Reinstall flow (toggle gateway off then on)
- Reset flow (click reset button, confirm, verify all state cleared)
- Gateway startup counter updates every second without UI blocking
- Navigation blocked while install is in progress
- Calendar versioning compatibility (2026.2.15 compatible with 2026.2.16)
**Edge cases checked:**
- Missing PATH (pnpm not in shell profile) → installer adds to PATH automatically
- Missing pnpm → error message shown, install button disabled
- Stale gateway (old version) → reinstall flow stops old gateway before starting new one
- Stale disable marker (`~/.config/openclaw/disable-launchagent`) → auto-cleared on fresh startup
- Gateway startup failure (port already in use) → error message shown, reset button available
- @MainActor contention → fixed: counter updates live, no blocking
**What I did NOT verify:**
- Windows/Linux onboarding flows (unchanged, out of scope)
- Gateway runtime behavior under load (unchanged, existing validation covers this)
- Web provider flows (unchanged)
## Compatibility / Migration
- **Backward compatible?** Yes
- **Config/env changes?** No (only adds new launchd service)
- **Migration needed?** No
- **Automatic migration**: Existing installs continue working unchanged; new onboarding flow only affects fresh installs
## Failure Recovery (if this breaks)
**How to disable/revert this change quickly:**
- Run `openclaw gateway stop` to stop the launchd service
- Run `launchctl bootout gui/$UID/ai.openclaw.gateway` to remove launchd plist
- Remove `~/Library/pnpm/openclaw` to uninstall CLI
- Remove `~/.openclaw` and `~/Library/Application Support/OpenClaw/identity` to clear all state
**Files/config to restore:**
- Revert to previous OpenClaw.app version (no config changes required)
**Known bad symptoms reviewers should watch for:**
- Gateway never starts (counter stuck at 0 or low number)
- Install button does nothing (check Console.app for errors)
- Navigation permanently disabled (isInstallBusy never resets)
- Reset button clears state but doesn't allow retry
- Device auth errors after gateway startup failure
## Risks and Mitigations
- **Risk**: Install button runs `npm install -g openclaw@latest` which could fail on network errors or permission issues.
- **Mitigation**: Error handling shows user-friendly message and keeps install button enabled for retry. Install log written to `~/Library/Logs/OpenClaw/install.log` for debugging.
- **Risk**: Gateway startup polling loop using `await` subprocess calls could still block UI on slow systems.
- **Mitigation**: Refactored polling to only read synchronous `mgr.status` property. Heavy subprocess work (`lsof`, `launchctl`) moved outside polling loop.
- **Risk**: Calendar versioning compatibility check might incorrectly accept incompatible versions if major version format changes.
- **Mitigation**: Test coverage for 2026.x.x format; semantic versioning fallback still works for non-calendar versions.
- **Risk**: Reset button could leave partial state if process is interrupted mid-clear.
- **Mitigation**: Each clear operation (CLI, gateway, device auth, wizard state) is independent and retryable. Worst case: user runs reset again.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added in-app CLI installer and gateway manager to the macOS onboarding flow, eliminating manual terminal setup. The Install page (now page 2 in the wizard) handles CLI installation via button click, automatic gateway startup with live progress counter, and a reset button for troubleshooting.
## Key changes
- **New Install page**: In-app CLI install button runs `install-cli.sh`, gateway toggle installs/starts launchd service with 60s timeout and live counter updates
- **Gateway startup reliability**: Fixed @MainActor contention in polling loop by reading synchronous `status` property instead of async health checks; increased timeout to 15s for cold Node starts
- **Calendar versioning**: Changed compatibility check from semver (same major + not older) to calendar-based (2026.x.x compatible with any 2026.y.y)
- **Reset functionality**: `resetInstallation()` stops gateway, removes launchd service, wipes `~/.openclaw`, clears device auth tokens; `restart-mac.sh` gained `--reset-onboarding` and `--full-reset` flags
- **Auth error handling**: `isGatewayAuthFailure()` detects device token mismatches after resets and marks gateway as attached (auth pending) instead of failed
- **Stale marker cleanup**: Auto-clears `disable-launchagent` marker when app is Developer ID signed (left by unsigned dev builds)
## Issues found
- URL mismatch: `CLIInstaller.swift:89` uses `openclaw.bot/install-cli.sh` but UI shows users `openclaw.ai/install-cli.sh`
<h3>Confidence Score: 4/5</h3>
- Safe to merge with one URL fix required
- The implementation is thorough with good error handling, proper state management, and comprehensive test coverage. The URL mismatch between actual installer script (`openclaw....
Most Similar PRs
#8260: fix(macOS): gateway readiness detection + reversible Configure later
by xksteven · 2026-02-03
78.3%
#12234: gateway: incident tracking, recover command, and ciao ERR_SERVER_CL...
by levineam · 2026-02-09
75.4%
#20555: fix(gateway): detect launchd supervision via XPC_SERVICE_NAME
by dimat · 2026-02-19
74.5%
#23301: Gateway: prevent dev reset from touching default profile state
by tristanmanchester · 2026-02-22
72.9%
#23364: Gateway: add risk-ack interlock for dangerous Control UI flags
by bmendonca3 · 2026-02-22
71.4%
#11455: fix(gateway): default gateway.mode to local when unset
by AnonO6 · 2026-02-07
71.2%
#18236: macOS daemon: bootstrap LaunchAgent on gateway start after stop
by agisilaos · 2026-02-16
70.8%
#17392: Add testing infrastructure and expand gateway OAuth scopes
by jordanhubbard · 2026-02-15
70.6%
#19801: fix: pre-check write permissions before global install to prevent E...
by menhguin · 2026-02-18
70.4%
#22102: fix(cron): default isolated jobs to fresh sessions with sessionReus...
by k-velorum · 2026-02-20
68.8%