Install
$ agentstack add skill-ariaxhan-the-agent-library-build-and-release-ios-app ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Build and Release an iOS App
> Status: draft. This v1 body only covers the headless TestFlight upload path. Before publishing, > expand it into the full build-and-release lifecycle.
What this is
A fastlane setup that builds, signs, and uploads an iOS (and macOS Catalyst) app to TestFlight with one credential: an App Store Connect API key (.p8). No interactive Apple ID login, no portal clicking for signing, no certs to restore on a fresh machine. The key mints the distribution cert and provisioning profile on demand, so a brand-new CI runner needs nothing but the .p8, the key ID, and the issuer ID.
When to use
- Headless CI/CD where you cannot do a browser-based Apple Sign-In.
- A fresh machine with no signing assets restored.
- You want store metadata + screenshots reproducible from versioned files, not hand-typed.
- Works for native Xcode projects, Expo (
expo prebuild), and Capacitor (npx cap sync ios).
Prerequisites
- An App Store Connect API key with App Manager / Admin role. Three values:
key_id, issuer_id, and the .p8 file (keep it gitignored, never commit it).
- Xcode +
fastlaneinstalled. AReleasescheme that archives. - Automatic signing left on in the target (
CODE_SIGN_STYLE=Automatic). - The app record already exists in App Store Connect (see "The one manual gate").
The procedure
All lanes call app_store_connect_api_key(...) first: it stuffs the token into the lane context (Spaceship::ConnectAPI), which is how produce, upload_to_testflight, and deliver authenticate without a login. They have no api_key of their own to pass it.
- Register the app record (first run only).
produce with skip_devcenter: true. This creates only the App Store Connect record via the token-auth API. We skip the Developer-Portal half because that uses legacy Apple-ID web login the key can't satisfy, and we don't need it: the App ID in the portal gets auto-created by xcodebuild -allowProvisioningUpdates during the build.
- Build + upload to TestFlight (
:beta).
build_app is the one action with no api_key param, so auth is threaded through xcargs instead: `` xcargs: "DEVELOPMENT_TEAM=YOUR_TEAM_ID CODE_SIGN_STYLE=Automatic " \ "-allowProvisioningUpdates " \ "-authenticationKeyID YOUR_KEY_ID " \ "-authenticationKeyIssuerID YOUR_ISSUER_ID " \ "-authenticationKeyPath #{absolute_path_to_p8}" ` The -authenticationKeyPath **must be absolute**: relative paths silently fail to authenticate. File.expandpath("../keys/AuthKeyXXXX.p8", __dir__) from the Fastfile. Then uploadtotestflight(apikey: apikey, skipwaitingforbuildprocessing: true)`.
- Push metadata (
:metadata).
upload_to_app_store with skip_binary_upload: true, skip_screenshots: true, force: true. Fields live in fastlane/metadata/. force: true suppresses the interactive HTML preview so it runs unattended.
- Push screenshots (
:screenshots).
upload_to_app_store with skip_binary_upload: true, skip_metadata: true, overwrite_screenshots: true, force: true, reading from fastlane/screenshots/.
- macOS Catalyst build (
:mac).
Same as :beta plus catalyst_platform: "macos" in build_app and app_platform: "osx" in upload_to_testflight. With SUPPORTS_MACCATALYST=YES and DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER=NO in the target, the Mac build shares the same bundle id and ASC record as iOS (Universal Purchase): no separate record.
- macOS screenshots (
:mac_screenshots).
upload_to_app_store(platform: "osx", screenshots_path: "./fastlane/screenshots-mac"). Catalyst screenshots are 2880×1800; deliver auto-maps that size to the APP_DESKTOP display type. You don't name the display type yourself.
- Mint the Mac installer cert key-only (
:mac_cert), if uploading a Catalyst build.
The ASC API can create certificates (POST /v1/certificates), so cert(platform: "macos", type: "mac_installer_distribution", api_key: api_key) generates the CSR, creates + downloads the cert, and imports it to the keychain. No portal click. Idempotent: reuses an existing valid cert.
Gotchas & failure modes
app_store_connect_api_keymust run first, in every lane. Ifproduce/deliver/
pilot prompts for an Apple ID, you forgot it or it ran after.
build_apphas noapi_key: authenticate viaxcargs -authenticationKey*. Easy to
pass the key everywhere except the build and then wonder why signing prompts for login.
-authenticationKeyPathmust be ABSOLUTE. Relative path = silent auth failure.producewithoutskip_devcenter: truefalls back to legacy web login (Apple ID +
password) for the portal half → forces an interactive login. Always skip devcenter.
- Expo / Capacitor regenerate the project (
expo prebuild --clean,
npx cap sync ios) and wipe signing build settings: that's exactly why DEVELOPMENT_TEAM + CODE_SIGN_STYLE go through xcargs, not the project file. For Capacitor: run the web build + npx cap sync ios before the lane.
- Reused build number is auto-rejected by TestFlight. Keep the build number ahead of
the latest processed build; bump it before every upload.
force: trueis required onupload_to_app_storefor unattended runs, or it opens
an HTML preview and blocks waiting for a human.
The one manual gate
Honest caveat: the very first creation of the App Store Connect app record can require a one-time interactive web session in some Apple accounts (produce via the key works for many, but Apple occasionally gates brand-new record creation behind a logged-in session). After the record exists, everything above is fully key-only and headless forever. Treat it like a one-time account bootstrap, the same shape as the first Catalyst installer cert.
Minimal example
lane :beta do
api_key = app_store_connect_api_key(
key_id: "YOUR_KEY_ID", issuer_id: "YOUR_ISSUER_ID",
key_filepath: "keys/AuthKey_XXXX.p8",
)
auth_key_path = File.expand_path("../keys/AuthKey_XXXX.p8", __dir__)
build_app(
workspace: "ios/App.xcworkspace", scheme: "App", configuration: "Release",
export_method: "app-store",
export_options: { signingStyle: "automatic", teamID: "YOUR_TEAM_ID" },
xcargs: "DEVELOPMENT_TEAM=YOUR_TEAM_ID CODE_SIGN_STYLE=Automatic " \
"-allowProvisioningUpdates " \
"-authenticationKeyID YOUR_KEY_ID " \
"-authenticationKeyIssuerID YOUR_ISSUER_ID " \
"-authenticationKeyPath #{auth_key_path}",
)
upload_to_testflight(api_key: api_key, skip_waiting_for_build_processing: true)
end
Full commented template with every lane: reference/Fastfile.example.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ariaxhan
- Source: ariaxhan/the-agent-library
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.