Skip to content

tddworks/asc-cli

Repository files navigation

asc-cli

App Store Command Center — inspired by the Terran Command Center from StarCraft.

CI codecov Swift Platform

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.

Quick Start

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 \
  --name personal        # optional alias; defaults to "default"

asc apps list          # find your app ID
asc init --app-id <id> # pin it — skip --app-id on every future command

Features

Category What you can do
Apps & Versions List apps, create versions, link builds, submit for App Store review
Builds Archive Xcode projects, export IPA/PKG, upload to App Store Connect, 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; submit builds for beta review
Monetization IAPs (consumable, non-consumable, non-renewing); subscriptions, offers, pricing, offer codes
Code Signing Bundle IDs, certificates, devices, provisioning profiles
Authentication Multi-account credential management; named accounts, active-account switching
Project Init asc init pins app context to .asc/project.json; auto-detects from .xcodeproj
Customer Reviews Read customer reviews, respond to feedback, and manage review responses
App Clips Manage App Clips, default experiences, and locale-specific card content
Game Center Manage achievements and leaderboards for your game
Plugins Install executable plugins in ~/.asc/plugins/ for custom event handlers
Reports Sales, subscription, installs, and financial reports; multi-step analytics workflow
Iris (Private API) Cookie-based auth; create apps, list apps via the iris private API that powers the ASC web UI
Simulators List, boot, shutdown local iOS simulators; interactive browser stream with tap, swipe, type via AXe
AI Agents JSON output with CAEOAS affordances — agents navigate without knowing the command tree

Requirements

  • macOS 13+
  • App Store Connect API key (create one here)
  • Swift 6.2+ (only needed when building from source)

Installation

Homebrew (recommended)

brew install tddworks/tap/asccli

Build from source

git clone https://github.com/tddworks/asc-cli.git
cd asc-cli
swift build -c release
cp .build/release/asc /usr/local/bin/

Authentication

Persistent login (recommended)

# Single account (saves as "default")
asc auth login \
  --key-id YOUR_KEY_ID \
  --issuer-id YOUR_ISSUER_ID \
  --private-key-path ~/.asc/AuthKey_XXXXXX.p8

# Multiple accounts
asc auth login --key-id K1 --issuer-id I1 --private-key-path work.p8 --name work
asc auth login --key-id K2 --issuer-id I2 --private-key-path personal.p8 --name personal

asc auth update --vendor-number 88012345  # save vendor number for reports
asc auth list            # list all saved accounts
asc auth use work        # switch active account
asc auth check           # → shows active account name + source: "file"
asc auth logout          # remove active account
asc auth logout --name personal  # remove a specific account

Credentials are saved to ~/.asc/credentials.json. All asc commands use the active account automatically — no environment variables needed per session. Account names must not contain spaces.

Environment variables (alternative)

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.

Command Reference

Auth & Project

asc auth login --key-id <id> --issuer-id <id> --private-key-path <path> [--name alias] [--vendor-number <n>]
asc auth update [--name alias] --vendor-number <number>
asc auth list
asc auth use <name>
asc auth check
asc auth logout [--name alias]

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 needed

Apps & Versions

asc 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.com

Builds & TestFlight

asc builds list [--app-id <id>] [--platform <ios|macos|tvos|visionos>] [--version <version>]
asc builds next-number --app-id <id> --version <version> --platform <platform>
asc builds archive --scheme MyApp [--platform ios] [--export-method app-store] [--upload --app-id <id> --version 1.0.0 --build-number 42]
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>

asc beta-review submissions list --build-id <id>
asc beta-review submissions create --build-id <id>
asc beta-review submissions get --submission-id <id>
asc beta-review detail get --app-id <id>
asc beta-review detail update --detail-id <id> [--contact-first-name <name>] [--notes <text>]

Xcode Cloud

asc xcode-cloud products list [--app-id <id>]
asc xcode-cloud workflows list --product-id <id>
asc xcode-cloud builds list --workflow-id <id>
asc xcode-cloud builds get --build-run-id <id>
asc xcode-cloud builds start --workflow-id <id> [--clean]

Customer Reviews

# List all reviews for an app
asc reviews list --app-id <id>

# Get a specific review
asc reviews get --review-id <id>

# Respond to a review
asc review-responses create --review-id <id> --response-body "Thank you for your feedback!"

# Get the response to a review
asc review-responses get --review-id <id>

# Delete a response
asc review-responses delete --response-id <id>

Game Center

# Get Game Center configuration (detail-id needed for subsequent commands)
asc game-center detail get --app-id <id>

# Achievements
asc game-center achievements list --detail-id <id>
asc game-center achievements create --detail-id <id> --reference-name "First Steps" --vendor-identifier first_steps --points 10
asc game-center achievements create --detail-id <id> --reference-name <n> --vendor-identifier <v> --points <n> [--show-before-earned] [--repeatable]
asc game-center achievements delete --achievement-id <id>

# Leaderboards
asc game-center leaderboards list --detail-id <id>
asc game-center leaderboards create --detail-id <id> --reference-name "All Time High" --vendor-identifier all_time_high --score-sort-type DESC
asc game-center leaderboards create --detail-id <id> --reference-name <n> --vendor-identifier <v> --score-sort-type ASC|DESC [--submission-type BEST_SCORE|MOST_RECENT_SCORE]
asc game-center leaderboards delete --leaderboard-id <id>

Power & Performance

# App-level performance metrics (launch time, hang rate, memory, etc.)
asc perf-metrics list --app-id <id>
asc perf-metrics list --app-id <id> --metric-type LAUNCH
asc perf-metrics list --build-id <id> --metric-type HANG

# Diagnostic signatures (hang/disk-write/launch hotspots)
asc diagnostics list --build-id <id>
asc diagnostics list --build-id <id> --diagnostic-type HANGS

# Diagnostic logs (call stacks for a signature)
asc diagnostic-logs list --signature-id <id>

Metadata

# 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 & Previews

# 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]

App Shots (AI screenshot generation)

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

Monetization

# 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>

# Subscription Offer Codes
asc subscription-offer-codes list --subscription-id <id>
asc subscription-offer-codes create --subscription-id <id> --name "SUMMER2026" --duration ONE_MONTH --mode FREE_TRIAL --periods 1 --eligibility NEW --offer-eligibility STACKABLE
asc subscription-offer-codes update --offer-code-id <id> --active false
asc subscription-offer-code-custom-codes list --offer-code-id <id>
asc subscription-offer-code-custom-codes create --offer-code-id <id> --custom-code "SUMMER2026" --number-of-codes 1000
asc subscription-offer-code-one-time-codes list --offer-code-id <id>
asc subscription-offer-code-one-time-codes create --offer-code-id <id> --number-of-codes 5000 --expiration-date 2026-12-31

# IAP Offer Codes
asc iap-offer-codes list --iap-id <id>
asc iap-offer-codes create --iap-id <id> --name "FREEGEMS" --eligibility NON_SPENDER
asc iap-offer-codes update --offer-code-id <id> --active false
asc iap-offer-code-custom-codes list --offer-code-id <id>
asc iap-offer-code-custom-codes create --offer-code-id <id> --custom-code "FREEGEMS100" --number-of-codes 500
asc iap-offer-code-one-time-codes list --offer-code-id <id>
asc iap-offer-code-one-time-codes create --offer-code-id <id> --number-of-codes 3000 --expiration-date 2026-06-30

Code Signing

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>

Team Management

# List all team members
asc users list

# Filter by role
asc users list --role DEVELOPER --output table

# Update a member's roles
asc users update --user-id <id> --role APP_MANAGER --role DEVELOPER

# Revoke access (e.g. on offboarding)
asc users remove --user-id <id>

# List pending invitations
asc user-invitations list

# Invite a new member
asc user-invitations invite --email new@example.com --first-name Alex --last-name Smith --role DEVELOPER

# Cancel a pending invitation
asc user-invitations cancel --invitation-id <id>

Reports

# Daily sales (latest — --report-date optional for DAILY only)
# --vendor-number auto-resolved from active account if saved via auth login/update
asc sales-reports download --report-type SALES --sub-type SUMMARY --frequency DAILY

# Weekly/monthly/yearly require --report-date
asc sales-reports download --report-type SUBSCRIPTION --sub-type SUMMARY --frequency MONTHLY --report-date 2024-01

# Financial report (--report-date always required)
asc finance-reports download --report-type FINANCIAL --region-code US --report-date 2024-01

# Explicit vendor number override
asc sales-reports download --vendor-number <n> --report-type SALES --sub-type SUMMARY --frequency DAILY

# Analytics (multi-step workflow)
asc analytics-reports request --app-id <id> --access-type ONE_TIME_SNAPSHOT
asc analytics-reports list --app-id <id>
asc analytics-reports reports --request-id <id> --category COMMERCE
asc analytics-reports instances --report-id <id> --granularity DAILY
asc analytics-reports segments --instance-id <id>

Plugins

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.uploaded

Iris (Private API)

# Check cookie session status
asc iris status --pretty

# List apps via iris
asc iris apps list --pretty

# Create a new app
asc iris apps create --name "My App" --bundle-id com.example.app --sku com.example.app --pretty

# Multi-platform with custom version
asc iris apps create --name "My App" --bundle-id com.example.app --sku MYSKU \
  --platforms IOS MAC_OS --version 2.0

Authentication: log in to appstoreconnect.apple.com in your browser — cookies are extracted automatically. For CI/CD, set ASC_IRIS_COOKIES.

Simulators

# List available iOS simulators
asc simulators list --output table
asc simulators list --booted --pretty

# Boot / shutdown
asc simulators boot --udid <udid>
asc simulators shutdown --udid <udid>

# Interactive stream to browser (tap, swipe, type via AXe)
asc simulators stream                           # pick device in browser
asc simulators stream --udid <udid> --fps 10    # direct stream

Requires AXe for interaction: brew install cameroncooke/axe/axe

Output & TUI

asc 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 back

Release Workflow

A full App Store release from build upload to review submission:

# 1. Upload build and wait for processing
# Option A: Archive from Xcode project and upload in one step
asc builds archive --scheme MyApp --upload --app-id APP_ID --version 1.2.0 --build-number 55
# Option B: Upload a pre-built IPA/PKG
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"

Feature Guides

Detailed documentation for each feature:

  • Auth — multi-account credential management; login, list, use, 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
  • Beta Review — submit builds for beta app review, manage review contact details
  • Xcode Cloud — products, workflows, build runs, start builds
  • Builds Archive — archive Xcode projects, export IPA/PKG, optional upload chaining
  • 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.json format and architecture
  • Users & Roles — team member management, role assignment, invitation lifecycle; directory integration for automated access control
  • Customer Reviews — list reviews, respond to feedback, manage review responses
  • Game Center — achievements (list, create, delete) and leaderboards (list, create, delete)
  • Power & Performance — performance metrics (app/build), diagnostic signatures, diagnostic logs
  • Reports — sales, finance, and analytics reports; TSV parsing, multi-step analytics workflow
  • Iris (Private API) — cookie-based auth; create apps, list apps via the iris private API
  • Simulators — list, boot, shutdown, interactive browser stream with AXe

Design: CAEOAS

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-abc
{
  "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
  }
}

Affordances are state-aware — submitForReview only appears when isEditable == true. See docs/design.md for the full pattern.

Use as a Swift Package (SPM)

asc-cli exposes an ASCKit library product so you can embed App Store Connect automation directly into your own Swift tool, script, or app without using the CLI binary.

Add the dependency

In your Package.swift:

dependencies: [
    .package(url: "https://github.com/tddworks/asc-cli.git", from: "0.1.0"),
],
targets: [
    .target(
        name: "MyTool",
        dependencies: [
            .product(name: "ASCKit", package: "asc-cli"),
        ]
    ),
]

Example usage

import Domain
import Infrastructure

// 1. Provide credentials (inline, env vars, or your own AuthProvider)
let credentials = AuthCredentials(
    keyID: "YOUR_KEY_ID",
    issuerID: "YOUR_ISSUER_ID",
    privateKeyPEM: """
    -----BEGIN PRIVATE KEY-----
    ...
    -----END PRIVATE KEY-----
    """
)

// 2. A simple inline AuthProvider that wraps fixed credentials
struct StaticAuthProvider: AuthProvider {
    let credentials: AuthCredentials
    func resolve() throws -> AuthCredentials { credentials }
}

// 3. Create any repository via ClientFactory
let factory = ClientFactory()
let authProvider = StaticAuthProvider(credentials: credentials)

let appRepo = try factory.makeAppRepository(authProvider: authProvider)
let apps = try await appRepo.listApps(limit: 50)
apps.data.forEach { print($0.name, $0.bundleID) }

// Build repository example
let buildRepo = try factory.makeBuildRepository(authProvider: authProvider)
let builds = try await buildRepo.listBuilds(appId: "YOUR_APP_ID", limit: 10)

Available factories (ClientFactory)

ClientFactory provides a make* method for every domain area:

Method Repository protocol
makeAppRepository AppRepository
makeBuildRepository BuildRepository
makeVersionRepository VersionRepository
makeTestFlightRepository TestFlightRepository
makeScreenshotRepository ScreenshotRepository
makeAppInfoRepository AppInfoRepository
makeSubmissionRepository SubmissionRepository
makeInAppPurchaseRepository InAppPurchaseRepository
makeSubscriptionRepository SubscriptionRepository
makeGameCenterRepository GameCenterRepository
makeUserRepository UserRepository
makeReportRepository / makeAnalyticsReportRepository ReportRepository / AnalyticsReportRepository
makeCustomerReviewRepository CustomerReviewRepository
makeCertificateRepository / makeProfileRepository / makeDeviceRepository Code-signing repositories
makeXcodeCloudProductRepository XcodeCloudProductRepository
… and more see Sources/Infrastructure/Client/ClientFactory.swift

Development

swift build          # build
swift test           # run tests (Chicago School TDD)
swift format --in-place --recursive Sources Tests

Architecture:

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.

Sponsors

Apps that use and support asc-cli development:

AppNexus
AppNexus for App Store Connect

App Wall

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.

License

MIT

About

App Store Connect from your terminal & Agents. A Swift CLI for managing your iOS and macOS apps on App Store Connect. Submit versions, manage screenshots, track builds — with full AI-agent support via CAEOAS affordances.

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors