# OpenClaw iOS Versioning OpenClaw iOS release uploads use an explicit CalVer release version. The committed repo no longer has an iOS-only version manifest; release commands must name the App Store train they are uploading to. ## Goals - make App Store release intent explicit at upload time - avoid stale committed iOS pins - keep Apple bundle fields valid for App Store Connect - keep normal local builds aligned with the current gateway release version - generate App Store release notes from an iOS-owned changelog ## Version model Release uploads require a version argument: ```bash pnpm ios:release:upload -- --version 2026.6.11 ``` Use `--build-number` when the build number is known or has been verified from App Store Connect: ```bash pnpm ios:release:upload -- --version 2026.6.11 --build-number 3 ``` The release version must use `YYYY.M.D` CalVer, for example `2026.4.6` or `2026.6.11`. When no explicit release version is supplied to the version helper, iOS derives its default version from root `package.json.version` after stripping supported release suffixes: - gateway `2026.4.10` -> iOS default `2026.4.10` - gateway `2026.4.10-beta.3` -> iOS default `2026.4.10` - gateway `2026.4.10-2` -> iOS default `2026.4.10` ## Apple bundle mapping Release version `2026.6.11` maps to: - `CFBundleShortVersionString = 2026.6.11` - `CFBundleVersion = numeric build number only` Fastlane can resolve the next build number by querying App Store Connect for the explicit short version. Maintainers may still pass `--build-number` to make the upload fully deterministic. ## Source of truth and generated files ### Source files - `package.json` - default iOS version source for local builds - explicit `--version` - release upload source of truth - `apps/ios/CHANGELOG.md` - iOS-only changelog and release-note source - `apps/ios/VERSIONING.md` - workflow and constraints ### Generated or derived files - `apps/ios/build/Version.xcconfig` - local gitignored build override generated per build or release prep - `apps/ios/SwiftSources.input.xcfilelist` - local gitignored Swift lint input file generated before Xcode project generation - temporary Fastlane metadata - release notes generated from `apps/ios/CHANGELOG.md` during metadata upload ## Tooling surfaces - `scripts/lib/ios-version.ts` - validates iOS CalVer - normalizes gateway version -> iOS CalVer - renders release notes from the iOS changelog - `scripts/ios-version.ts` - CLI for JSON, shell, or single-field version reads - accepts `--version YYYY.M.D` for explicit release queries - `scripts/ios-sync-versioning.ts` - validates that release notes can be rendered from the default or explicit iOS version - `scripts/ios-write-version-xcconfig.sh` - writes the local numeric build override file in `apps/ios/build/Version.xcconfig` - `scripts/ios-write-swift-filelist.mjs` - writes the local Swift file list consumed by Xcode pre-build lint phases - `scripts/ios-release-prepare.sh` - requires `--version` and prepares App Store distribution signing and bundle settings - `apps/ios/fastlane/Fastfile` - resolves version metadata from the explicit release version - creates or verifies Developer Portal bundle IDs/services through Fastlane `produce` - syncs encrypted App Store signing assets with Fastlane `match` - resolves App Store Connect build numbers for the explicit short version when needed - uploads screenshots, release notes, and the rendered App Review PDF attachment before archiving Agent-driven App Store uploads must use `pnpm ios:release:upload` as the only release path. If that command fails, stop at the failing screenshot, metadata, archive, validation, or upload step. Do not continue by archiving and uploading manually with `pnpm ios:release:archive`, `asc builds upload`, `asc release stage`, `asc publish appstore`, direct Fastlane lanes, or other App Store Connect mutation commands. ## Release-note resolution order When generating the temporary Fastlane release notes metadata, the tooling reads the first available changelog section in this order: 1. exact release version, for example `## 2026.6.11` 2. `## Unreleased` Before production upload, prefer a final `## ` section and validate with the same version: ```bash pnpm ios:version:check -- --version 2026.6.11 ``` ## Common commands ```bash pnpm ios:version pnpm ios:version -- --version 2026.6.11 pnpm ios:version:check pnpm ios:filelist:gen pnpm ios:release:upload -- --version 2026.6.11 --build-number 3 ``` ## Normal App Store Connect build iteration workflow 1. choose the App Store release train explicitly, for example `2026.6.11` 2. update `apps/ios/CHANGELOG.md` under `## ` or `## Unreleased` 3. run `pnpm ios:version:check -- --version ` 4. check App Store Connect for the latest build number when needed 5. upload another build with `pnpm ios:release:upload -- --version --build-number ` This keeps the version decision at the release command instead of in a committed state file. ## Release SHA tracking Successful App Store Connect uploads create a non-tag Git ref that records the source commit for the uploaded store build: ```text refs/openclaw/mobile-releases/ios/- ``` Example: ```text refs/openclaw/mobile-releases/ios/2026.6.11-3 ``` These refs are intentionally outside `refs/tags/*` and `refs/heads/*`. They do not appear on GitHub release or tag pages, and they do not participate in the core OpenClaw release machinery. `pnpm ios:release:upload` checks the ref before archive/upload work and records it only after the App Store Connect upload succeeds. Existing refs are immutable: the same ref at the same SHA is accepted, while the same ref at a different SHA fails. Do not create this ref after a manual fallback upload. The ref is release-lane evidence, not a repair mechanism for a failed `pnpm ios:release:upload` run. Useful direct commands: ```bash pnpm mobile:release:preflight -- --platform ios --version 2026.6.11 --build 3 pnpm mobile:release:resolve -- --platform ios --version 2026.6.11 --build 3 ``` ## New release workflow When you want the next production iOS release to align with the current gateway release: 1. confirm the root gateway version: ```bash node -e "console.log(require('./package.json').version)" ``` 2. update `apps/ios/CHANGELOG.md` for that release 3. validate iOS release notes: ```bash pnpm ios:version:check -- --version 2026.6.11 ``` 4. verify live App Store Connect state and choose the next build number 5. upload with explicit release intent: ```bash pnpm ios:release:upload -- --version 2026.6.11 --build-number 3 ``` 6. manually submit the reviewed build for App Review in App Store Connect 7. release the approved build to production ## Important invariant App Store uploads must carry explicit version intent. Do not infer a release train from generated local files. App Review submission remains manual. Automation may create/update the editable App Store version, upload screenshots, upload release notes, upload the App Review PDF attachment, and upload builds, but it should not upload the App Store Connect `Notes` field or submit a build for review. For agent-driven releases, a failed `pnpm ios:release:upload` is terminal for that attempt. Agents must report the failed step and wait for maintainer direction instead of switching to lower-level App Store Connect upload or submission commands.