A CLI for App Store Connect — automate builds, releases, TestFlight, subscriptions, and screenshots from your terminal or CI pipeline. Outputs structured JSON so AI agents can drive the full release workflow.
brew install tddworks/tap/asccli
asc auth login \
--key-id YOUR_KEY_ID \
--issuer-id YOUR_ISSUER_ID \
--private-key-path ~/.asc/AuthKey_XXXXXX.p8
asc apps list # find your app ID
asc init --app-id <id> # pin it — skip --app-id on every future command| Category | What you can do |
|---|---|
| Apps & Versions | List apps, create versions, link builds, submit for App Store review |
| Builds | Upload IPA/PKG, wait for processing, distribute to TestFlight, update beta notes |
| Metadata | Update What's New, description, and keywords per locale |
| App Info | Set per-locale name, subtitle, privacy policy; manage categories and age rating |
| Screenshots | Create screenshot sets and upload images |
| App Previews | Upload video previews (.mp4, .mov, .m4v) per locale and device size |
| App Shots | AI-powered screenshot generation via Gemini; translate to any locale in one command |
| TestFlight | Manage beta groups; add/remove/import/export testers |
| Monetization | IAPs (consumable, non-consumable, non-renewing); subscriptions, offers, pricing |
| Code Signing | Bundle IDs, certificates, devices, provisioning profiles |
| Project Init | asc init pins app context to .asc/project.json; auto-detects from .xcodeproj |
| Plugins | Install executable plugins in ~/.asc/plugins/ for custom event handlers |
| AI Agents | JSON output with CAEOAS affordances — agents navigate without knowing the command tree |
- macOS 13+
- App Store Connect API key (create one here)
- Swift 6.2+ (only needed when building from source)
brew install tddworks/tap/asccligit clone https://github.com/tddworks/asc-cli.git
cd asc-cli
swift build -c release
cp .build/release/asc /usr/local/bin/asc auth login \
--key-id YOUR_KEY_ID \
--issuer-id YOUR_ISSUER_ID \
--private-key-path ~/.asc/AuthKey_XXXXXX.p8
asc auth check # → shows source: "file"
asc auth logout # remove saved credentialsCredentials are saved to ~/.asc/credentials.json. All asc commands pick them up automatically — no environment variables needed per session.
export ASC_KEY_ID="YOUR_KEY_ID"
export ASC_ISSUER_ID="YOUR_ISSUER_ID"
export ASC_PRIVATE_KEY_PATH="~/.asc/AuthKey_XXXXXX.p8"
# or: export ASC_PRIVATE_KEY="<PEM content>"Resolution order: ~/.asc/credentials.json → environment variables.
asc auth login --key-id <id> --issuer-id <id> --private-key-path <path>
asc auth check
asc auth logout
asc init # auto-detect app from *.xcodeproj bundle ID
asc init --name "My App" # search by name
asc init --app-id <id> # pin directly — no API call neededasc apps list
asc versions list --app-id <id>
asc versions create --app-id <id> --version <v> --platform ios
asc versions set-build --version-id <id> --build-id <id>
asc versions check-readiness --version-id <id>
asc versions submit --version-id <id>
asc version-review-detail get --version-id <id>
asc version-review-detail update --version-id <id> --contact-first-name Jane --contact-email dev@example.comasc builds list [--app-id <id>]
asc builds upload --app-id <id> --file MyApp.ipa --version 1.0.0 --build-number 42
asc builds uploads list --app-id <id>
asc builds uploads get --upload-id <id>
asc builds uploads delete --upload-id <id>
asc builds add-beta-group --build-id <id> --beta-group-id <id>
asc builds remove-beta-group --build-id <id> --beta-group-id <id>
asc builds update-beta-notes --build-id <id> --locale en-US --notes "What's new"
asc testflight groups list [--app-id <id>]
asc testflight testers list --beta-group-id <id>
asc testflight testers add --beta-group-id <id> --email user@example.com
asc testflight testers remove --beta-group-id <id> --tester-id <id>
asc testflight testers import --beta-group-id <id> --file testers.csv
asc testflight testers export --beta-group-id <id># Version localizations (What's New, description, keywords)
asc version-localizations list --version-id <id>
asc version-localizations create --version-id <id> --locale zh-Hans
asc version-localizations update --localization-id <id> --whats-new "Bug fixes"
# App info localizations (name, subtitle, privacy policy)
asc app-infos list --app-id <id>
asc app-infos update --app-info-id <id> --primary-category GAMES --primary-subcategory-one GAMES_ACTION
asc app-categories list [--platform IOS]
asc app-info-localizations list --app-info-id <id>
asc app-info-localizations create --app-info-id <id> --locale zh-Hans --name "我的应用"
asc app-info-localizations update --localization-id <id> --name "My App" --subtitle "Do things faster"
asc app-info-localizations delete --localization-id <id>
# Age rating
asc age-rating get --app-info-id <id>
asc age-rating update --declaration-id <id> --violence-realistic NONE --gambling false --kids-age-band NINE_TO_ELEVEN# Screenshots
asc screenshot-sets list --localization-id <id>
asc screenshot-sets create --localization-id <id> --display-type APP_IPHONE_67
asc screenshots list --set-id <id>
asc screenshots upload --set-id <id> --file ./screen.png
# Video previews
asc app-preview-sets list --localization-id <id>
asc app-preview-sets create --localization-id <id> --preview-type IPHONE_67
asc app-previews list --set-id <id>
asc app-previews upload --set-id <id> --file ./preview.mp4 [--preview-frame-time-code 00:00:05]asc app-shots config --gemini-api-key KEY # save key once
asc app-shots generate # iPhone 6.9" at 1320×2868 (default)
asc app-shots generate --device-type APP_IPHONE_67 # iPhone 6.7"
asc app-shots generate --device-type APP_IPAD_PRO_129 # iPad 13"
asc app-shots generate --style-reference ~/ref.png # match visual style of reference image
asc app-shots translate --to zh --to ja # localize all screens in parallel
asc app-shots translate --to ko --device-type APP_IPHONE_67
asc app-shots translate --to zh --style-reference ~/ref.png# In-App Purchases
asc iap list --app-id <id>
asc iap create --app-id <id> --reference-name <n> --product-id <id> --type consumable
asc iap submit --iap-id <id>
asc iap price-points list --iap-id <id> [--territory USA]
asc iap prices set --iap-id <id> --base-territory USA --price-point-id <id>
asc iap-localizations list --iap-id <id>
asc iap-localizations create --iap-id <id> --locale en-US --name <n>
# Subscriptions
asc subscription-groups list --app-id <id>
asc subscription-groups create --app-id <id> --reference-name <n>
asc subscriptions list --group-id <id>
asc subscriptions create --group-id <id> --name <n> --product-id <id> --period ONE_MONTH
asc subscriptions submit --subscription-id <id>
asc subscription-localizations list --subscription-id <id>
asc subscription-localizations create --subscription-id <id> --locale en-US --name <n>
asc subscription-offers list --subscription-id <id>
asc subscription-offers create --subscription-id <id> --duration ONE_MONTH --mode FREE_TRIAL --periods 1
asc subscription-offers create --subscription-id <id> --duration THREE_MONTHS --mode PAY_AS_YOU_GO --periods 3 --price-point-id <id>asc bundle-ids list [--platform ios|macos|universal] [--identifier com.example.app]
asc bundle-ids create --name "My App" --identifier com.example.app --platform ios
asc bundle-ids delete --bundle-id-id <id>
asc certificates list [--type IOS_DISTRIBUTION]
asc certificates create --type IOS_DISTRIBUTION --csr-content "$(cat MyApp.certSigningRequest)"
asc certificates revoke --certificate-id <id>
asc devices list [--platform ios|macos]
asc devices register --name "My iPhone" --udid <udid> --platform ios
asc profiles list [--bundle-id-id <id>] [--type IOS_APP_STORE]
asc profiles create --name "My Profile" --type IOS_APP_STORE --bundle-id-id <id> --certificate-ids <id>
asc profiles delete --profile-id <id>asc plugins list
asc plugins install ./my-plugin
asc plugins uninstall --name slack-notify
asc plugins enable --name slack-notify
asc plugins disable --name slack-notify
asc plugins run --name slack-notify --event build.uploadedasc apps list # JSON (default)
asc apps list --output table # aligned table
asc apps list --output markdown # markdown table
asc apps list --output json --pretty # pretty-printed JSON
asc tui # interactive browser — arrow keys, Enter to drill in, Escape to go backA full App Store release from build upload to review submission:
# 1. Upload build and wait for processing
asc builds upload --app-id APP_ID --file ./MyApp.ipa --version 1.2.0 --build-number 55 --wait
# 2. Distribute to TestFlight
GROUP_ID=$(asc testflight groups list --app-id APP_ID | jq -r '.data[0].id')
BUILD_ID=$(asc builds list --app-id APP_ID | jq -r '.data[0].id')
asc builds add-beta-group --build-id "$BUILD_ID" --beta-group-id "$GROUP_ID"
asc builds update-beta-notes --build-id "$BUILD_ID" --locale en-US --notes "What's new in 1.2.0"
# 3. Prepare the App Store version
VERSION_ID=$(asc versions list --app-id APP_ID | jq -r '.data[0].id')
asc versions set-build --version-id "$VERSION_ID" --build-id "$BUILD_ID"
# 4. Update What's New
LOC_ID=$(asc version-localizations list --version-id "$VERSION_ID" | jq -r '.data[0].id')
asc version-localizations update --localization-id "$LOC_ID" --whats-new "Bug fixes and performance improvements"
# 5. Pre-flight check, then submit
asc versions check-readiness --version-id "$VERSION_ID" --pretty
asc versions submit --version-id "$VERSION_ID"Detailed documentation for each feature:
- Auth — persistent credential storage, login/logout/check
- Version Localizations — What's New, description, keywords
- Screenshots — screenshot sets and image uploads
- App Previews — preview sets and video uploads
- App Info — name, subtitle, privacy policy, categories, age rating
- TestFlight — beta groups, tester management, CSV import/export
- Builds Upload — upload IPA/PKG, TestFlight distribution, beta notes
- Code Signing — bundle IDs, certificates, devices, profiles
- Version Check-Readiness — pre-flight submission checks
- In-App Purchases & Subscriptions — IAPs, subscriptions, offers, pricing
- App Shots — AI-powered screenshot generation and localization
- Plugins — custom event handlers (Slack, Telegram, webhooks)
- App Wall — community showcase;
apps.jsonformat and architecture
REST has HATEOAS — responses embed URLs so clients navigate without knowing the API. This CLI has CAEOAS (Commands As the Engine Of Application State): responses embed ready-to-run CLI commands so agents navigate without memorising the command tree.
$ asc versions list --app-id app-abcAffordances are state-aware — submitForReview only appears when isEditable == true. See docs/design.md for the full pattern.
swift build # build
swift test # run tests (Chicago School TDD)
swift format --in-place --recursive Sources TestsArchitecture:
Sources/
├── Domain/ # Pure value types, @Mockable protocols — zero I/O
├── Infrastructure/ # SDK adapters (appstoreconnect-swift-sdk), parent ID injection
└── ASCCommand/ # CLI commands, output formatting, TUI
Unidirectional dependency: ASCCommand → Infrastructure → Domain
Dependencies:
See CHANGELOG.md for version history.
Apps that use and support asc-cli development:
AppNexus for App Store Connect
Apps built and published using asc-cli. To add yours, edit homepage/apps.json and open a pull request — see docs/features/app-wall.md for the format.
View the live wall at asccli.app/#app-wall.
MIT
{ "id": "v1", "versionString": "2.1.0", "state": "PREPARE_FOR_SUBMISSION", "isEditable": true, "affordances": { "listLocalizations": "asc version-localizations list --version-id v1", "checkReadiness": "asc versions check-readiness --version-id v1", "submitForReview": "asc versions submit --version-id v1" // only when isEditable == true } }