storebound/skills/appstore-first-release/SKILL.md

7.2 KiB

name description
appstore-first-release Step-by-step first (and later) App Store release of a mobile app or game - App Store Connect API key, bundle id, app record, signing and xcodebuild archive/upload with the API key, TestFlight, version + listing text in many locales, screenshots, age rating, App Privacy, review details, in-app purchases with the first version, and submitting for review. Use when the user wants to publish, release, upload or set up an iOS app or game on the App Store or TestFlight, or hits App Store Connect API errors.

App Store: first release

The CLI is storebound (on PATH while the plugin is enabled; otherwise bunx storebound in a project that has it, or bun <toolchain>/cli/index.ts; agents can also use the storebound mcp tools). Config: storebound.config.ts; credentials: ASC_KEY_ID, ASC_ISSUER_ID, ASC_P8 (env or .storebound/credentials.json, gitignored). All commands are idempotent and have --dry. Run storebound check first.

Ask the owner before submitting for review, releasing, or canceling a submission. The final "Submit for Review" of a first version is the owner's click. Shared agent rules: docs/agents-core.md of the toolchain.

Steps (API = storebound, UI = App Store Connect / Xcode by hand)

  1. UI · API key. App Store Connect > Users and Access > Integrations > App Store Connect API > Team Keys > + (Admin or App Manager). Download AuthKey_<KEYID>.p8 once, keep it in ~/.appstoreconnect/private_keys/, note the Key ID and Issuer ID. The same key signs builds (-allowProvisioningUpdates).
  2. API · Bundle id. storebound apple bundle registers it (Certificates, Identifiers & Profiles).
  3. UI · App record. Apps > + > New App: iOS, name, primary language, the bundle id, SKU. No API for this. Then storebound apple status finds it (put the Apple ID in apple.appId to skip the lookup).
  4. Local · Info.plist. ITSAppUsesNonExemptEncryption with the true answer (export-compliance skill; NO only when the app uses nothing beyond OS / HTTPS encryption) so builds arrive answered; NSUserTrackingUsageDescription if ads use the IDFA; privacy policy reachable inside the app (guideline 5.1.1).
  5. Local · Build + upload (Mac, no Xcode account login needed, the API key does signing):
    K="-allowProvisioningUpdates -authenticationKeyPath $ASC_P8 -authenticationKeyID $ASC_KEY_ID -authenticationKeyIssuerID $ASC_ISSUER_ID"
    xcodebuild -project ios/App/App.xcodeproj -scheme App -configuration Release -destination generic/platform=iOS \
      -archivePath build/App.xcarchive MARKETING_VERSION=1.0.0 CURRENT_PROJECT_VERSION=3 $K archive
    xcodebuild -exportArchive -archivePath build/App.xcarchive -exportOptionsPlist ExportOptions.plist -exportPath build/export $K
    
    ExportOptions.plist: method app-store-connect, destination upload, teamID , signingStyle automatic. MARKETING_VERSION / CURRENT_PROJECT_VERSION overrides beat the project values. Take the build number from storebound apple next-build right before archiving and note it: every later step selects that exact build, never "the latest". Processing takes 5-30 min (storebound apple status shows VALID).
  6. API · TestFlight. Put an internal group with allBuilds: true in apple.testflight.groups and run storebound apple testflight groups: every new build reaches the team automatically. External testers, What to Test, Test Information and Beta App Review: the testflight skill. Sandbox testers stay UI: Users and Access > Sandbox.
  7. API · Version + text. Fill store/appstore.md, then storebound apple listing --version 1.0.0 --build 3 (version, copyright, MANUAL release, the build with exactly that number, name / subtitle / privacy URL, description / keywords / promo / URLs). Then storebound apple release --phased on: manual release + phased release is the default for every version (release-management).
  8. API · Screenshots. store-screenshots skill, then storebound apple screenshots > .storebound/asc-shots.log 2>&1 & (6.9" + 6.5" per locale, MD5-idempotent).
  9. API · App info. storebound apple appinfo: categories, age rating declaration, content rights, Free price, all territories. The first availability record of a new app may be refused by the public API (an error on POST /v2/appAvailabilities); then set it once in App Store Connect > Pricing and Availability and re-run (later runs only read it).
  10. API · Review details. storebound apple review-details (contact from .storebound/credentials.json reviewContact, or --contact-from <Apple ID of another app of the team>; notes from the config). Apps behind a sign-in: the demo account from .storebound/ (review-access skill). Apps with accounts: in-app deletion (account-deletion skill).
  11. API + UI · In-app purchases and subscriptions. store-iap-setup and store-subscriptions skills. First IAPs and subscriptions go to review with this version.
  12. UI · App Privacy. store-declarations skill (nutrition labels), then Publish.
  13. Preflight. storebound validate --apple until it shows no blocker (store-preflight).
  14. UI · Submit. Version page > Add for Review (with the IAPs in the same draft submission) > Submit for Review (owner). Release type MANUAL means the owner presses "Release" after approval.
  15. Verify + wait. storebound apple status: version WAITING_FOR_REVIEW, IAPs WAITING_FOR_REVIEW, one review submission. storebound apple status --wait-review polls until approved (exit 0) or rejected (exit 1, review-rejections). Approved: the owner releases (release-management).

Gotchas

  • The app record cannot be created via API; the bundle id can.
  • First consumable / non-consumable IAPs must be submitted together with an app version, only from the IAP page ("Add for Review" puts them into the draft submission). The API (inAppPurchaseSubmissions) answers FIRST_*_MUST_BE_SUBMITTED_ON_VERSION. If the version was already submitted without them: cancel the review submission (storebound apple status --cancel-submission <id>, PATCH canceled: true), wait a minute, add the IAPs from their page, then resubmit.
  • App Privacy (data types, purposes, linked, tracking) is UI-only and must be published, not just saved.
  • Export compliance unanswered = "Missing Compliance": storebound apple encryption (export-compliance).
  • ITMS-91053 / 91061 privacy manifest emails after upload: privacy-manifest skill.
  • Screenshot sizes: 6.9" 1320 x 2868 (APP_IPHONE_67) is required; 6.5" 1284 x 2778 (APP_IPHONE_65) recommended. PNG without alpha. Up to 10 per set. Apple processes uploads async; failures show as FAILED later.
  • App Store icon (1024) must have no alpha channel (storebound icons writes rgb24).
  • Limits: name 30, subtitle 30, promotional text 170, keywords 100 bytes (UTF-8, no spaces after commas), description 4000. No "What's New" on a first version.
  • Guideline 5.1.1: the privacy policy link must be inside the app too (Settings > Privacy), not only in the listing.
  • xcodebuild with Capacitor needs a UTF-8 locale (export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8).
  • 500 / 503 from the API happen; storebound retries with backoff.