OpenClaw iOS (Super Alpha)
This iPhone app is super-alpha and internal-use only. It connects to an OpenClaw Gateway as a role: node.
Distribution Status
- Public distribution: not available.
- Internal beta distribution: local archive + TestFlight upload via Fastlane.
- Local/manual deploy from source via Xcode remains the default development path.
Super-Alpha Disclaimer
- Breaking changes are expected.
- UI and onboarding flows can change without migration guarantees.
- Foreground use is the only reliable mode right now.
- Treat this build as sensitive while permissions and background behavior are still being hardened.
Exact Xcode Manual Deploy Flow
- Prereqs:
- Xcode 16+
pnpmxcodegen- Apple Development signing set up in Xcode
- From repo root:
pnpm install
./scripts/ios-configure-signing.sh
cd apps/ios
xcodegen generate
open OpenClaw.xcodeproj
- In Xcode:
- Scheme:
OpenClaw - Destination: connected iPhone (recommended for real behavior)
- Build configuration:
Debug - Run (
Product->Run)
- Scheme:
- If signing fails on a personal team:
- Use unique local bundle IDs via
apps/ios/LocalSigning.xcconfig. - Start from
apps/ios/LocalSigning.xcconfig.example.
- Use unique local bundle IDs via
Shortcut command (same flow + open project):
pnpm ios:open
Local Beta Release Flow
Prereqs:
- Xcode 16+
pnpmxcodegenfastlane- Apple account signed into Xcode for automatic signing/provisioning
- App Store Connect API key set up in Keychain via
scripts/ios-asc-keychain-setup.shwhen auto-resolving a beta build number or uploading to TestFlight
Release behavior:
- Local development keeps using unique per-developer bundle IDs from
scripts/ios-configure-signing.sh. - Beta release uses canonical
ai.openclaw.client*bundle IDs through a temporary generated xcconfig inapps/ios/build/BetaRelease.xcconfig. - Beta release also switches the app to
OpenClawPushTransport=relay,OpenClawPushDistribution=official, andOpenClawPushAPNsEnvironment=production. - The beta flow does not modify
apps/ios/.local-signing.xcconfigorapps/ios/LocalSigning.xcconfig. apps/ios/version.jsonis the pinned iOS release version source.apps/ios/CHANGELOG.mdis the iOS-only changelog and release-note source.- The pinned iOS version must use CalVer like
2026.4.10. - That pinned value becomes:
CFBundleShortVersionString = 2026.4.10CFBundleVersion = next TestFlight build number for 2026.4.10
- Changing the root gateway version does not change the iOS app version until you explicitly pin from the gateway.
- See
apps/ios/VERSIONING.mdfor the full workflow.
Required env for beta builds:
OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.comThis must be a plainhttps://host[:port][/path]base URL without whitespace, query params, fragments, or xcconfig metacharacters.
Archive without upload:
pnpm ios:beta:archive
Archive and upload to TestFlight:
pnpm ios:beta
If you need to force a specific build number:
pnpm ios:beta -- --build-number 7
Maintainer Quick Release Checklist
Use this when a clone is missing local iOS release setup and you want the shortest path to a TestFlight upload.
- Confirm Fastlane auth is set up:
cd apps/ios
fastlane ios auth_check
- If auth is missing, bootstrap it once on this Mac:
scripts/ios-asc-keychain-setup.sh \
--key-path /absolute/path/to/AuthKey_XXXXXXXXXX.p8 \
--issuer-id YOUR_ISSUER_ID \
--write-env
This should create apps/ios/fastlane/.env with the non-secret ASC variables while the private key stays in Keychain.
- Set the official/TestFlight relay URL for the build:
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com
- If you are starting a brand-new production release train, pin iOS to the current gateway version first:
pnpm ios:version:pin -- --from-gateway
- Upload the beta:
pnpm ios:beta
-
Expected behavior:
- Fastlane reads
apps/ios/version.json - verifies synced iOS versioning artifacts
- resolves the next TestFlight build number for that short version
- generates
apps/ios/build/BetaRelease.xcconfig - archives
OpenClaw - uploads the IPA to TestFlight
- Fastlane reads
-
Expected outputs after a successful run:
apps/ios/build/beta/OpenClaw-<version>.ipaapps/ios/build/beta/OpenClaw-<version>.app.dSYM.zip- Fastlane log line like
Uploaded iOS beta: version=<version> short=<short> build=<build>
-
If this is a fresh clone on a maintainer machine that already works elsewhere, it is OK to copy the non-secret
apps/ios/fastlane/.envfrom another trusted local clone on the same Mac. The Keychain-backed private key remains machine-local and is not stored in the repo.
iOS Versioning Workflow
- Pinned iOS release version:
apps/ios/version.json - iOS-only changelog:
apps/ios/CHANGELOG.md - Generated checked-in artifacts:
apps/ios/Config/Version.xcconfigapps/ios/fastlane/metadata/en-US/release_notes.txt
- Useful commands:
pnpm ios:version
pnpm ios:version:check
pnpm ios:version:sync
pnpm ios:version:pin -- --from-gateway
pnpm ios:version:pin -- --version 2026.4.10
Recommended flow:
TestFlight iteration on an existing train
- Keep
apps/ios/version.jsonpinned to the current train version. - Update
apps/ios/CHANGELOG.md, usually under## Unreleasedwhile iterating. - Run
pnpm ios:version:syncafter changelog changes. - Upload more TestFlight builds with
pnpm ios:beta. - Let Fastlane bump only the numeric build number.
Starting the next production release train
- Pin iOS to the current gateway version:
pnpm ios:version:pin -- --from-gateway
- Update
apps/ios/CHANGELOG.mdfor the new release as needed. - Run
pnpm ios:version:sync. - Submit the first TestFlight build for that newly pinned version.
- Keep iterating on that same version until the release candidate is ready.
See apps/ios/VERSIONING.md for the detailed spec.
APNs Expectations For Local/Manual Builds
- The app calls
registerForRemoteNotifications()at launch. apps/ios/Sources/OpenClaw.entitlementssetsaps-environmenttodevelopment.- APNs token registration to gateway happens only after gateway connection (
push.apns.register). - Local/manual builds default to
OpenClawPushTransport=directandOpenClawPushDistribution=local. - Your selected team/profile must support Push Notifications for the app bundle ID you are signing.
- If push capability or provisioning is wrong, APNs registration fails at runtime (check Xcode logs for
APNs registration failed). - The gateway host also needs direct APNs auth configured separately with
OPENCLAW_APNS_TEAM_ID,OPENCLAW_APNS_KEY_ID, and eitherOPENCLAW_APNS_PRIVATE_KEY_P8orOPENCLAW_APNS_PRIVATE_KEY_PATH. - Recommended gateway-host storage for the APNs
.p8file is~/.openclaw/credentials/apns/AuthKey_<KEYID>.p8with restrictive permissions, then pointOPENCLAW_APNS_PRIVATE_KEY_PATHat that file. apps/ios/fastlane/.envonly covers App Store Connect / Fastlane auth; it does not provide gateway APNs credentials for local direct-push testing.- Debug builds default to
OpenClawPushAPNsEnvironment=sandbox; Release builds default toproduction.
APNs Expectations For Official Builds
- Official/TestFlight builds register with the external push relay before they publish
push.apns.registerto the gateway. - The gateway registration for relay mode contains an opaque relay handle, a registration-scoped send grant, relay origin metadata, and installation metadata instead of the raw APNs token.
- The relay registration is bound to the gateway identity fetched from
gateway.identity.get, so another gateway cannot reuse that stored registration. - The app persists the relay handle metadata locally so reconnects can republish the gateway registration without re-registering on every connect.
- If the relay base URL changes in a later build, the app refreshes the relay registration instead of reusing the old relay origin.
- Relay mode requires a reachable relay base URL and uses App Attest plus a StoreKit app transaction JWS during registration.
- Gateway-side relay sending is configured through
gateway.push.apns.relay.baseUrlinopenclaw.json.OPENCLAW_APNS_RELAY_BASE_URLremains a temporary env override only.
Official Build Relay Trust Model
iOS -> gateway- The app must pair with the gateway and establish both node and operator sessions.
- The operator session is used to fetch
gateway.identity.get.
iOS -> relay- The app registers with the relay over HTTPS using App Attest plus a StoreKit app transaction JWS.
- The relay requires the official production/TestFlight distribution path, which is why local Xcode/dev installs cannot use the hosted relay.
gateway delegation- The app includes the gateway identity in relay registration.
- The relay returns a relay handle and registration-scoped send grant delegated to that gateway.
gateway -> relay- The gateway signs relay send requests with its own device identity.
- The relay verifies both the delegated send grant and the gateway signature before it sends to APNs.
relay -> APNs- Production APNs credentials and raw official-build APNs tokens stay in the relay deployment, not on the gateway.
This exists to keep the hosted relay limited to genuine OpenClaw official builds and to ensure a gateway can only send pushes for iOS devices that paired with that gateway.
What Works Now (Concrete)
- Pairing via setup code flow (
/pairthen/pair approvein Telegram). - Gateway connection via discovery or manual host/port with TLS fingerprint trust prompt.
- Chat + Talk surfaces through the operator gateway session.
- iPhone node commands in foreground: camera snap/clip, canvas present/navigate/eval/snapshot, screen record, location, contacts, calendar, reminders, photos, motion, local notifications.
- Share extension deep-link forwarding into the connected gateway session.
Computer Use Relationship
The iOS app is not a Codex Computer Use backend. Computer Use and cua-driver mcp are macOS desktop-control paths; iOS exposes device capabilities as OpenClaw node commands through the gateway. Agents can drive the iPhone canvas, camera, screen, location, voice, and other node capabilities with node.invoke, subject to iOS foreground/background limits.
Location Automation Use Case (Testing)
Use this for automation signals ("I moved", "I arrived", "I left"), not as a keep-awake mechanism.
- Product intent:
- movement-aware automations driven by iOS location events
- example: arrival/exit geofence, significant movement, visit detection
- Non-goal:
- continuous GPS polling just to keep the app alive
Test path to include in QA runs:
- Enable location permission in app:
- set
Alwayspermission - verify background location capability is enabled in the build profile
- set
- Background the app and trigger movement:
- walk/drive enough for a significant location update, or cross a configured geofence
- Validate gateway side effects:
- node reconnect/wake if needed
- expected location/movement event arrives at gateway
- automation trigger executes once (no duplicate storm)
- Validate resource impact:
- no sustained high thermal state
- no excessive background battery drain over a short observation window
Pass criteria:
- movement events are delivered reliably enough for automation UX
- no location-driven reconnect spam loops
- app remains stable after repeated background/foreground transitions
Known Issues / Limitations / Problems
- Foreground-first: iOS can suspend sockets in background; reconnect recovery is still being tuned.
- Background command limits are strict:
canvas.*,camera.*,screen.*, andtalk.*are blocked when backgrounded. - Background location requires
Alwayslocation permission. - Pairing/auth errors intentionally pause reconnect loops until a human fixes auth/pairing state.
- Voice Wake and Talk contend for the same microphone; Talk suppresses wake capture while active.
- APNs reliability depends on local signing/provisioning/topic alignment.
- Expect rough UX edges and occasional reconnect churn during active development.
Current In-Progress Workstream
Automatic wake/reconnect hardening:
- improve wake/resume behavior across scene transitions
- reduce dead-socket states after background -> foreground
- tighten node/operator session reconnect coordination
- reduce manual recovery steps after transient network failures
Debugging Checklist
- Confirm build/signing baseline:
- regenerate project (
xcodegen generate) - verify selected team + bundle IDs
- regenerate project (
- In app
Settings -> Gateway:- confirm status text, server, and remote address
- verify whether status shows pairing/auth gating
- If pairing is required:
- run
/pair approvefrom Telegram, then reconnect
- run
- If discovery is flaky:
- enable
Discovery Debug Logs - inspect
Settings -> Gateway -> Discovery Logs
- enable
- If network path is unclear:
- switch to manual host/port + TLS in Gateway Advanced settings
- In Xcode console, filter for subsystem/category signals:
ai.openclaw.iosGatewayDiagAPNs registration failed
- Validate background expectations:
- repro in foreground first
- then test background transitions and confirm reconnect on return