Skip to content
Mobile
Skill

/ios-app-store-submit

Build, sign, and submit a Flutter/iOS app to the App Store Connect — covers Xcode archive/export, code signing (including headless-Mac keychain workarounds), the `asc` CLI for App Store Connect metadata automation, screenshot handoff, and final review submission. Use when asked

BOOST
From plugin
ios-app-store-submit
1431 skill
Install
$ npx -y skills add zestfulpulse/ios-app-store-submit --skill ios-app-store-submit --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/ios-app-store-submit

Context preview

The summary Claude sees to decide when to auto-load this skill.

Build, sign, and submit a Flutter/iOS app to the App Store Connect — covers Xcode archive/export, code signing (including headless-Mac keychain workarounds), the `asc` CLI for App Store Connect metadata automation, screenshot handoff, and final review submission. Use when asked

SKILL.md

ios-app-store-submit.SKILL.md
name: ios-app-store-submit
description: Build, sign, and submit a Flutter/iOS app to the App Store Connect — covers Xcode archive/export, code signing (including headless-Mac keychain workarounds), the `asc` CLI for App Store Connect metadata automation, screenshot handoff, and final review submission. Use when asked to build and upload an iOS app, set up App Store code signing, fix a rejected/failed App Store Connect upload, automate App Store Connect metadata, or submit an app for App Store review. Triggers: "빌드해서 제출", "App Store 제출", "archive and upload", "TestFlight에 올려줘", "asc CLI로 메타데이터".

iOS App Store Build & Submit

End-to-end playbook for taking a Flutter/iOS app from "code is done" to "submitted for App Store review," written for headless/agent-driven Mac environments (no interactive Xcode GUI session, no GUI keychain prompts available). Validated end-to-end on a real submission (2026-08-05) that hit — and worked around — every pitfall documented below.

**This skill is project-agnostic.** Never hardcode bundle IDs, App Store Connect App IDs, Team IDs, or certificate names from a prior run — always derive them from the current project (see Step 0).

When NOT to use this

  • Pure UI/feature work with no build/signing/submission component — just do the work directly.
  • If the user has an interactive Xcode session open and wants to do signing themselves — offer to guide them through Xcode's GUI instead of fighting headless keychain limitations for no reason.

Step 0 — Discover the project

Before anything else, gather facts from the current project (don't ask the user for things you can read yourself):

# Bundle ID, team ID, current device family
grep -n "PRODUCT_BUNDLE_IDENTIFIER\|DEVELOPMENT_TEAM\|TARGETED_DEVICE_FAMILY" ios/Runner.xcodeproj/project.pbxproj | sort -u

# App version / build number
grep "^version:" pubspec.yaml   # Flutter: X.Y.Z+N

# Is asc CLI already installed and authenticated?
which asc && asc auth status

# Is this app already registered in App Store Connect?
asc apps list --output table

If `asc` isn't installed or there's no cached auth, walk the user through generating an App Store Connect API key (they must do this themselves — only the account holder/Admin can): 1. https://appstoreconnect.apple.com/access/integrations/api → generate key → **App Manager** role (least privilege that still covers everything this skill needs) → download the `.p8` immediately (one-time download). 2. Get the file to you as a file (Drive link, etc.), never ask them to paste the raw key text in chat. Save it under `~/.asc/keys/` with `chmod 600`. 3. Register it:

   asc auth login --name "<project>" --key-id "<KEY_ID>" --issuer-id "<ISSUER_ID>" \
     --private-key "~/.asc/keys/AuthKey_<KEY_ID>.p8" --network --bypass-keychain

**`--bypass-keychain` is required in headless sessions** — plain `asc auth login` fails with `-25308 User interaction is not allowed` because macOS Keychain wants a GUI unlock prompt that doesn't exist here.

Step 1 — iOS Simulator does not work for ML/vision-heavy apps on Apple Silicon

If the app uses `google_mlkit_*` (or similar plugins shipping arm64-simulator-incomplete binaries), **the app cannot even install on any iOS Simulator on an Apple Silicon Mac** ("Failed to find matching arch for input file"). Don't waste time debugging this — confirm real-device testing is the only option for that Mac, and check `flutter devices` for a wirelessly-paired iPhone/iPad before assuming none is available.

For screenshots specifically: if simulators are unusable, **don't fabricate screens**. Ask the user to capture the real screens on their device, or use `xcrun devicectl` to install/launch things yourself if the device is paired (see Step 6).

Step 2 — Code signing (the actual hard part)

2a. The core headless-Mac problem

The **login keychain requires interactive unlock** in most agent/headless sessions. Any operation that touches it — `asc auth login` without `--bypass-keychain`, `security import` into `login.keychain`, or even `codesign` using an *existing* identity that's already in `login.keychain` — can fail with `-25308 User interaction is not allowed` or `errSecInternalComponent`. This is true even for identities that work fine when the same Mac is used interactively (e.g., via a prior Xcode session).

**Fix: use a dedicated, non-interactive keychain for the whole session**, exactly like a CI runner would:

KC_PASS="build-$(date +%s | tail -c 6)"
security create-keychain -p "$KC_PASS" build.keychain
security unlock-keychain -p "$KC_PASS" build.keychain
security set-keychain-settings -lut 21600 build.keychain
security list-keychains -d user -s build.keychain login.keychain

Keep `$KC_PASS` around (write it to a gitignored file) — you'll need it again for `security set-key-partition-list`.

2b. Generate certificates without ever touching a keychain interactively

`asc certificates create --generate-csr` creates the private key and CSR as **plain files** — no keychain interaction at all — then submits the CSR to Apple:

asc certificates list --output table   # check what already exists first
asc certificates create --certificate-type IOS_DISTRIBUTION --generate-csr \
  --key-out ./signing/dist.key --csr-out ./signing/dist.csr \
  --common-name "<App> Distribution" --email "<contact-email>"
# For a real-device dev/profile build later, also:
# asc certificates create --certificate-type IOS_DEVELOPMENT --generate-csr ...

Fetch/create the matching provisioning profile:

asc signing fetch --bundle-id "<bundle.id>" --profile-type IOS_APP_STORE \
  --certificate-type IOS_DISTRIBUTION --create-missing --output ./signing
# For device installs: --profile-type IOS_APP_DEVELOPMENT --device "<ASC device ID>"
# (asc devices list to find/confirm the device is already registered)

2c. Import into build.keychain — OpenSSL 3.x needs `-legacy`

openssl x509 -inform
Read more
Ships withios-app-store-submit

From automating App Store submission to deciding whether an iOS app is actually ready to submit, and helping recover when review fails.

Get the whole plugin
Stats
143
Stars
18
Forks
Active
Maintenance
Python
Language
MIT
License
22d ago
Last commit
2mo ago
Created
4h ago
Added

Repo: zestfulpulse/ios-app-store-submit