dbmrq/agent-skills/ios-app-store-release

Claude Code and agent skill by dbmrq/agent-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Ship iOS apps to App Store Connect end-to-end — Xcode Cloud, ASC API metadata and screenshots, release manifests, TestFlight, and prepare-for-submission without auto-submit. Use when publishing an iOS app, setting up App Store automation, ASC API scripts, store screenshots, Xcode Cloud release workflows, or preparing a version for App Review.

Install

npx vskill@latest install dbmrq/agent-skills/ios-app-store-release

SKILL.md

iOS App Store Release

Agent playbook for repeatable, mostly-automated iOS releases. Assumes Swift/SwiftUI, optional XcodeGen, Python ASC client, and Xcode Cloud for archives.

Out of scope (agent already knows): creating Apple Developer accounts, basic xcodebuild, writing App Store copy from scratch, generic git tagging.

Hard rules (never violate)

These are stop-and-ask constraints. Convenience (unblocking asc-sync, bumping a marketing version, “fixing” a stuck ship) does not override them.

  1. Never blind-overwrite ASC listing or review data. Live App Store Connect is the source of truth when it differs from the repo or from what an agent “remembers.” Always GET before PATCH; merge per ASC metadata merge; prefer ASC (or the richer side) for review notes, description, keywords, contact, etc. Local review-notes.txt / YAML being non-empty is not permission to replace a longer ASC value. After merge, write winners back into store-assets/ so the next ship does not regress.
  1. Never remove a version from App Review (no DELETE /appStoreVersionSubmissions, no “Cancel Review” / withdraw, no developer-reject-to-edit) unless the human explicitly asks in this conversation. Canceling restarts the review clock and can add days of wait. If a version is already WAITING_FOR_REVIEW / IN_REVIEW / PENDING_APPLE_RELEASE, follow Version selection — upload the binary only and warn; do not cancel, rename, or re-attach builds on that version.
  1. Do not invent a workaround that mutates an in-review version (rename 1.0→1.1, swap the attached build, rewrite notes) without explicit human approval. Prefer waiting for approval/release, or uploading a new TestFlight/App Store build while leaving the review queue alone.

Before starting

Collect per-app constants (store in scripts/asc/constants.py or equivalent):

ConstantExampleNotes
APP_IDASC apps resource idNot bundle id
BUNDLE_IDco.example.app
DEFAULT_LOCALEen-US
CI_PRODUCT_NAMEApp name in Xcode CloudMay lag in ASC API after first workflow setup
Screenshot display typesAPP_IPHONE_67, APP_IPAD_PRO_3GEN_129Validate against ASC — invalid enums fail upload
Composed pixel sizesiPhone 1290×2796, iPad 2064×2752Must match display type

Credentials: ~/.config/app-store-connect/credentials.json with issuer_id, key_id, private_key_path, optional team_id.

bash
pip install -r scripts/requirements-asc.txt # PyJWT, requests, pyyaml, Pillow

Target architecture (per app repo)

releases/<version>.yaml # ship intent: version, whats_new, flags
store-assets/
metadata/<locale>.yaml # keywords, URLs, copyright, review contact
metadata/review-notes.txt
scenes.yaml # screenshot scenes → display type + raw path
composed/ # marketing frames (generated)
scripts/
release.py # orchestrator: validate → test → bump → tag → wait → assets → asc-sync → submit
asc/{client,metadata,builds,screenshots,submit}.py
compose_store_assets.py
upload_store_assets.py
capture-screenshots.sh
check_xcode_cloud.py
ci_scripts/
ci_post_clone.sh # brew xcodegen + generate (if spec-driven)
ci_pre_xcodebuild.sh # sanity check generated .xcodeproj exists

Design choices that paid off:

  • Tests local, archive in Cloud — saves Cloud compute; only Release workflow on tag.
  • YAML manifest per release — agents edit ship intent, not ASC UI.
  • `submit_for_review: false` default for first ship — human presses Submit after visual check.
  • `.release-state.json` + `--resume` — idempotent recovery; skip completed steps with strict < ordering (failed step must re-run).
  • Legal/support URLs — separate public repo + GitHub Pages; app repo stays private.

Reference templates and API traps: reference.md.

End-to-end ship workflow

Copy and track:

- [ ] Version selection (query ASC versions; reuse editable or create next; never cancel in-review)
- [ ] ASC app record exists; target version ready (PREPARE_FOR_SUBMISSION)
- [ ] Legal pages live (privacy + support URLs reachable)
- [ ] Xcode Cloud Release workflow: correct *.xcodeproj path, tag trigger
- [ ] Demo/screenshot data isolated from Release builds (#if DEBUG)
- [ ] release manifest written
- [ ] Dry-run pipeline
- [ ] Ship (or resume)
- [ ] Verify readiness checklist
- [ ] Human: App Privacy questionnaire in ASC UI if Submit disabled
- [ ] Human: Submit for Review (unless auto-submit enabled)
1. Release manifest
yaml
version: "1.0"
whats_new: |
Initial release.
promotional_text: ""
refresh_assets: true
submit_for_review: false

whats_new required for validator even when ASC rejects it on first release (handle in metadata sync — see reference).

2. Orchestrator steps

Typical order:

  1. validate — manifest + required metadata fields
  2. tests — unit tests locally (GregorTests-style, not full UI suite)
  3. bump — MARKETING_VERSION + increment CURRENT_PROJECT_VERSION in project.yml, run xcodegen
  4. commit + tag — v{version}, push branch + tag (triggers Cloud)
  5. wait-build — poll Xcode Cloud product or ASC builds API until processingState: VALID
  6. assets (if refresh_assets) — capture → compose → upload screenshots
  7. asc-sync — metadata, review detail, export compliance, attach build
  8. submit (optional) — create submission; often blocked by API role or left to human
bash
./scripts/ship.sh ship releases/1.0.yaml --dry-run
./scripts/ship.sh ship releases/1.0.yaml
./scripts/ship.sh ship releases/1.0.yaml --resume
./scripts/ship.sh status --version 1.0
3. Build wait fallback

If find_ci_product() returns nothing (common right after first workflow setup), poll ASC builds:

python
GET /v1/builds?filter[app]={APP_ID}&include=preReleaseVersion&sort=-uploadedDate

Trap: build.attributes.version is the build number (e.g. 3), not marketing version. Match via included preReleaseVersions.attributes.version.

Trap: Xcode Cloud builds can be buildAudienceType: INTERNAL_ONLY (TestFlight-only) depending on the workflow's distribution setting. Only APP_STORE_ELIGIBLE builds can attach to an appStoreVersion; an internal build fails with 409 ENTITY_ERROR.RELATIONSHIP.INVALID — "The specified pre-release build could not be added." Filter on `buildAudienceType == APP_STORE_ELIGIBLE` inside the build selector, not only at attach time: Beta/TestFlight builds are usually the newest ones, so an unfiltered “latest VALID build” will always pick the wrong one. Prefer newer_than_build_id=<previous eligible build> over min_build_number — Xcode Cloud may stamp its own CI run number (28) while project.yml says 101, so a project-number floor can reject the real release build.

Workflow contract (enforce it before tagging): keep two workflows per app — Release on tag v* with APP_STORE_ELIGIBLE, and Beta on push to main with INTERNAL_ONLY for TestFlight/FeedbackLoop. Beta must never be App Store-eligible: a feedback-loop build must not be attachable to a version. Audit both via the ASC API (GET /ciProducts/{id}/workflows) or a scripts/asc/workflows.py audit helper; a missing Release workflow is the usual reason every build picker entry is grayed out. Creating a workflow is possible via POST /v1/ciWorkflows (needs product, primary repository, ciXcodeVersions “Latest Release”, and ciMacOsVersions “Latest Release” relationships). PATCHing a workflow replaces the start conditions you omit — to add manualBranchStartCondition, send tagStartCondition and manualTagStartCondition in the same PATCH or tag releases silently stop triggering.

Diagnosing “most builds are grayed out”: query /v1/builds and look at buildAudienceType. If the recent ones are all INTERNAL_ONLY and there is no Release workflow, the app has only a Beta/TestFlight pipeline. Add the Release workflow, run it from the tag/branch, wait for processingState: VALID, then attach that build. Do not try to attach a Beta build.

Local archive fallback when Cloud is broken: xcodebuild archive → exportArchive → xcrun altool --upload-app. Copy .p8 to ~/.appstoreconnect/private_keys/AuthKey_{KEY_ID}.p8 — altool ignores custom --apiKeyPath unless file is in that directory.

After upload, PATCH build: usesNonExemptEncryption: false (and set ITSAppUsesNonExemptEncryption = NO in Info.plist for future uploads).

Submitting for review (current API)

POST /v1/appStoreVersionSubmissions is not available to API keys anymore: it returns 403 FORBIDDEN_ERROR — The resource 'appStoreVersionSubmissions' does not allow 'CREATE'. Allowed operation is: DELETE. Use review submissions instead:

  1. POST /v1/reviewSubmissions with platform: IOS and the app relationship.
  2. POST /v1/reviewSubmissionItems with reviewSubmission + appStoreVersion.
  3. PATCH /v1/reviewSubmissions/{id} with submitted: true.

Trap — an open submission may not contain your app version. Creative assets (header/search images and videos) can be submitted separately and sit in WAITING_FOR_REVIEW while the version is still PREPARE_FOR_SUBMISSION. Before deciding “already submitted” or reusing a draft, list items with GET /reviewSubmissions/{id}/items?include=appStoreVersion and check for a matching appStoreVersion id. Multiple submissions can coexist; create a new one for the version if the open one only contains assets. Do not cancel the asset submission.

`whatsNew` is required for updates. ASC localizations are often empty while the release manifest has the notes. Merge/patch whatsNew before submitting (the manifest is the source for shipping copy); for a first release it may be non-editable and can be skipped.

A 409 STATE_ERROR.ENTITY_STATE_INVALID on item-create hides readiness blockers in meta.associatedErrors — surface them. Common current blockers:

  • STATE_ERROR.CANNOT_SUBMIT_MISSING_REGULATED_MEDICAL_DEVICE_APP_DECLARATION → App Store

Connect → App Information → Declare Regulated Medical Device (select No for a non-medical app). Required for apps with a primary/secondary Health & Fitness or Medical category, or frequent medical content in the age rating. UI-only, no public API.

  • App Privacy questionnaire (also UI-only).

Screenshots (non-obvious)

Deep capture / compose / ASC upload workflow: [ios-app-store-screenshots](../ios-app-store-screenshots/SKILL.md).

Summary for ship pipelines: raw simulator capture → compose_store_assets.py (Pillow + scenes.yaml) → upload_store_assets.py --version X.Y. Use XCTest attachments + SCREENSHOT_BASENAME export (do not rely on xcodebuild shell env for launch args). Pin simulator names; gate DemoMode with #if DEBUG.

Demo / mock data (critical)

Store screenshots need content; App Store builds must not.

  • Gate all demo vault seeding behind #if DEBUG and launch args (e.g. -UITestDemo).
  • Production: empty journal only (JournalBootstrap.ensureDefaultJournal — directories, no notes).
  • Review notes must describe real first-launch behavior (empty journal), not screenshot fixtures. First submissions follow the common-questions template in reference.md; the physical-device screen recording attachment is human-only in the ASC UI.
  • Never symlink or ship bundled sample markdown in the app target.

Xcode Cloud

`ci_post_clone.sh`: install/run xcodegen generate when .xcodeproj is generated from spec.

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
5

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/dbmrq/agent-skills/ios-app-store-release/badge)](https://verified-skill.com/skills/dbmrq/agent-skills/ios-app-store-release)

Something wrong with this skill or its page? Tell us.