OpenClaw iOS (Super Alpha)
This iOS app is super-alpha and internal-use only. The first public App Store release targets iPhone and connects to an OpenClaw Gateway as a role: node.
Distribution Status
- Public distribution: App Store Connect app created; production signing is configured through the App Store release Fastlane path.
- Internal TestFlight distribution: uses the same App Store distribution archive uploaded to App Store Connect.
- 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
App Store Release Flow
Prereqs:
- Xcode 16+
pnpmxcodegenfastlane- Apple account signed into Xcode for the canonical OpenClaw team (
FWJYW4S8P8) - Fastlane Apple Developer Portal session for the canonical OpenClaw team when creating bundle IDs or enabling services
- Release-owner access to the encrypted signing repo password (
MATCH_PASSWORD) - App Store Connect app already created for
ai.openclawfoundation.app - App Store Connect API key set up in Keychain via
scripts/ios-app-store-connect-keychain-setup.shwhen auto-resolving a build number or uploading to App Store Connect
Release behavior:
- Local development uses the canonical
ai.openclawfoundation.app*bundle IDs when the OpenClaw team is available, and uniqueai.openclawfoundation.app.test.*bundle IDs only for non-canonical fallback teams. - App Store release uses canonical
ai.openclawfoundation.app*bundle IDs through a temporary generated xcconfig inapps/ios/build/AppStoreRelease.xcconfig. - App Store release uses manual
Apple Distributionsigning with profile names pinned inapps/ios/Config/AppStoreSigning.json. - Fastlane owns one-time Developer Portal setup, encrypted
matchsigning sync to the repo/branch pinned inapps/ios/Config/AppStoreSigning.json, and release handling. - App Store release also switches the app to
OpenClawPushTransport=relay,OpenClawPushDistribution=official,OpenClawPushAPNsEnvironment=production, and a productionaps-environmententitlement. pnpm ios:release:uploadgenerates App Store screenshots and uploads release notes before archiving and uploading the IPA.pnpm ios:releaseremains a compatibility alias forpnpm ios:release:upload; prefer the explicit upload command in new release docs and automation.- App Review submission is manual in App Store Connect. The release lane uploads a build and metadata, but does not submit for review.
- The release 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 App Store Connect 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.
Relay behavior for App Store builds:
- Release builds default to
https://ios-push-relay.openclaw.ai. - Optional custom relay override:
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.
Signing setup commands:
pnpm ios:release:signing:plan
pnpm ios:release:signing:check
pnpm ios:release:signing:setup
MATCH_PASSWORD=... pnpm ios:release:signing:sync:push
MATCH_PASSWORD=... pnpm ios:release:signing:sync:pull
Release-owner secrets:
- App Store Connect API auth uses Keychain for private key material plus non-secret
apps/ios/fastlane/.envvariables. - The encrypted signing repo password lives outside this repo in the release-owner vault and is exposed locally as
MATCH_PASSWORD. - Apple Distribution private keys, certificates, provisioning profiles, and decrypted signing sync output stay under
apps/ios/build/or Keychain and are gitignored. - Rotating release signing means refreshing Fastlane
matchassets and pushing a fresh encrypted sync state.
Prepare the generated release xcconfig/project without archiving:
pnpm ios:release:prepare -- --build-number 7
Archive without upload:
pnpm ios:release:archive
Archive and upload to App Store Connect:
pnpm ios:release:upload
If you need to force a specific build number:
pnpm ios:release:upload -- --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 an App Store Connect 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-app-store-connect-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 non-secret App Store Connect variables while the private key stays in Keychain.
-
Confirm the App Store Connect app and Apple Developer identifiers/capabilities exist for:
ai.openclawfoundation.appai.openclawfoundation.app.shareai.openclawfoundation.app.activitywidgetai.openclawfoundation.app.watchkitappai.openclawfoundation.app.watchkitapp.extension
Use
pnpm ios:release:signing:setupfor the initial portal setup, thenMATCH_PASSWORD=... pnpm ios:release:signing:sync:pushto publish encrypted Fastlane match assets to the shared private repo. -
Optional: set a custom official relay URL for the build. If unset, the release flow uses
https://ios-push-relay.openclaw.ai.
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 build:
pnpm ios:release:upload
-
Expected behavior:
- Fastlane reads
apps/ios/version.json - verifies synced iOS versioning artifacts
- resolves the next App Store Connect build number for that short version
- generates deterministic App Store screenshots
- uploads release notes and screenshots to the editable App Store version
- generates
apps/ios/build/AppStoreRelease.xcconfig - archives
OpenClaw - uploads the IPA to App Store Connect for TestFlight/App Review use
- leaves App Review submission for a maintainer to complete manually
- Fastlane reads
-
Expected outputs after a successful run:
apps/ios/build/app-store/OpenClaw-<version>.ipaapps/ios/build/app-store/OpenClaw-<version>.app.dSYM.zip- Fastlane log line like
Uploaded iOS App Store build: 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:release:upload. - 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 App Store Connect 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.entitlementsderivesaps-environmentfrom the active build configuration/signing override.- APNs token registration to gateway happens only after gateway connection (
push.apns.register). - Local/manual builds default to
OpenClawPushTransport=direct,OpenClawPushDistribution=local, and a developmentaps-environmententitlement. - 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 QR or setup code flow (
/pair qror/pair, then/pair approvein Telegram). - Gateway connection via discovery or manual host/port with TLS fingerprint trust prompt.
- Chat + Talk surfaces through the operator gateway session.
- iOS node commands in foreground: camera snap/clip, canvas present/navigate/eval/snapshot, screen record, location, contacts, calendar, reminders, photos, motion, local notifications.
- Authenticated background
node.presence.alivebeacons that update gateway last-seen metadata when the app moves between foreground and background, without treating suspended sockets as connected. - 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.openclawfoundation.appGatewayDiagAPNs registration failed
- Validate background expectations:
- repro in foreground first
- then test background transitions and confirm reconnect on return