# asc-client A command-line tool for building, archiving, and publishing apps to the App Store — from Xcode archive to App Review submission. Built with Swift on the [App Store Connect API](https://developer.apple.com/documentation/appstoreconnectapi). > **Note:** Covers the core app release workflow: archiving, uploading builds, managing versions and localizations, screenshots, and review submission. More API coverage is planned. ## Requirements - macOS 13+ - Swift 6.0+ (only for building from source) ## Installation ### Homebrew ```bash brew tap keremerkan/tap brew install asc-client ``` The tap provides a pre-built binary for Apple Silicon Macs, so installation is instant. ### Download the binary Download the latest release from [GitHub Releases](https://github.com/keremerkan/asc-client/releases): ```bash curl -L https://github.com/keremerkan/asc-client/releases/latest/download/asc-client-macos-arm64.tar.gz -o asc-client.tar.gz tar xzf asc-client.tar.gz mv asc-client /usr/local/bin/ ``` Since the binary is not signed or notarized, macOS will quarantine it on first download. Remove the quarantine attribute: ```bash xattr -d com.apple.quarantine /usr/local/bin/asc-client ``` > **Note:** Pre-built binaries are provided for Apple Silicon (arm64) only. Intel Mac users should build from source. ### Build from source ```bash git clone https://github.com/keremerkan/asc-client.git cd asc-client swift build -c release strip .build/release/asc-client cp .build/release/asc-client /usr/local/bin/ ``` > **Note:** The release build takes a few minutes because the [asc-swift](https://github.com/aaronsky/asc-swift) dependency includes ~2500 generated source files covering the entire App Store Connect API surface. `strip` removes debug symbols, reducing the binary from ~175 MB to ~59 MB. ### Shell completions Set up tab completion for subcommands, options, and flags (supports zsh and bash): ```bash asc-client install-completions ``` This detects your shell and configures everything automatically. Restart your shell or open a new tab to activate. ## Setup ### 1. Create an API Key Go to [App Store Connect > Users and Access > Integrations > App Store Connect API](https://appstoreconnect.apple.com/access/integrations/api) and generate a new key. Download the `.p8` private key file. ### 2. Configure ```bash asc-client configure ``` This will prompt for your **Key ID**, **Issuer ID**, and the path to your `.p8` file. The private key is copied into `~/.asc-client/` with strict file permissions (owner-only access). ## Usage ### Apps ```bash # List all apps asc-client apps list # Show app details asc-client apps info # List App Store versions asc-client apps versions # Create a new version asc-client apps create-version asc-client apps create-version 2.1.0 --platform ios --release-type manual # Check review submission status asc-client apps review-status # Submit for review asc-client apps submit-for-review asc-client apps submit-for-review --version 2.1.0 ``` ### Build Management ```bash # Interactively select and attach a build to a version asc-client apps attach-build asc-client apps attach-build --version 2.1.0 # Attach the most recent build automatically asc-client apps attach-latest-build # Remove the attached build from a version asc-client apps detach-build ``` ### Localizations ```bash # View localizations (latest version by default) asc-client apps localizations asc-client apps localizations --version 2.1.0 --locale en-US # Export localizations to JSON asc-client apps export-localizations asc-client apps export-localizations --version 2.1.0 --output my-localizations.json # Update a single locale asc-client apps update-localization --whats-new "Bug fixes" --locale en-US # Bulk update from JSON file asc-client apps update-localizations --file localizations.json ``` The JSON format for export and bulk update: ```json { "en-US": { "description": "My app description.\n\nSecond paragraph.", "whatsNew": "- Bug fixes\n- New dark mode", "keywords": "productivity,tools,utility", "promotionalText": "Try our new features!", "marketingURL": "https://example.com", "supportURL": "https://example.com/support" }, "de-DE": { "whatsNew": "- Fehlerbehebungen\n- Neuer Dunkelmodus" } } ``` Only fields present in the JSON are updated -- omitted fields are left unchanged. ### Screenshots & App Previews ```bash # Download all screenshots and preview videos asc-client apps download-media asc-client apps download-media --folder my-media/ --version 2.1.0 # Upload screenshots and preview videos from a folder asc-client apps upload-media --folder media/ # Upload to a specific version asc-client apps upload-media --folder media/ --version 2.1.0 # Replace existing media in matching sets before uploading asc-client apps upload-media --folder media/ --replace ``` Organize your media folder with locale and display type subfolders: ``` media/ ├── en-US/ │ ├── APP_IPHONE_67/ │ │ ├── 01_home.png │ │ ├── 02_settings.png │ │ └── preview.mp4 │ └── APP_IPAD_PRO_3GEN_129/ │ └── 01_home.png └── de-DE/ └── APP_IPHONE_67/ ├── 01_home.png └── 02_settings.png ``` - **Level 1:** Locale (e.g. `en-US`, `de-DE`, `ja`) - **Level 2:** Display type folder name (see table below) - **Level 3:** Media files -- images (`.png`, `.jpg`, `.jpeg`) become screenshots, videos (`.mp4`, `.mov`) become app previews - Files are uploaded in alphabetical order by filename - Unsupported files are skipped with a warning #### Display types | Folder name | Device | Screenshots | Previews | |---|---|---|---| | `APP_IPHONE_67` | iPhone 6.7" (iPhone 16 Pro Max, 15 Pro Max, 14 Pro Max) | Yes | Yes | | `APP_IPHONE_61` | iPhone 6.1" (iPhone 16 Pro, 15 Pro, 14 Pro) | Yes | Yes | | `APP_IPHONE_65` | iPhone 6.5" (iPhone 11 Pro Max, XS Max) | Yes | Yes | | `APP_IPHONE_58` | iPhone 5.8" (iPhone 11 Pro, X, XS) | Yes | Yes | | `APP_IPHONE_55` | iPhone 5.5" (iPhone 8 Plus, 7 Plus, 6s Plus) | Yes | Yes | | `APP_IPHONE_47` | iPhone 4.7" (iPhone SE 3rd gen, 8, 7, 6s) | Yes | Yes | | `APP_IPHONE_40` | iPhone 4" (iPhone SE 1st gen, 5s, 5c) | Yes | Yes | | `APP_IPHONE_35` | iPhone 3.5" (iPhone 4s and earlier) | Yes | Yes | | `APP_IPAD_PRO_3GEN_129` | iPad Pro 12.9" (3rd gen+) | Yes | Yes | | `APP_IPAD_PRO_3GEN_11` | iPad Pro 11" | Yes | Yes | | `APP_IPAD_PRO_129` | iPad Pro 12.9" (1st/2nd gen) | Yes | Yes | | `APP_IPAD_105` | iPad 10.5" (iPad Air 3rd gen, iPad Pro 10.5") | Yes | Yes | | `APP_IPAD_97` | iPad 9.7" (iPad 6th gen and earlier) | Yes | Yes | | `APP_DESKTOP` | Mac | Yes | Yes | | `APP_APPLE_TV` | Apple TV | Yes | Yes | | `APP_APPLE_VISION_PRO` | Apple Vision Pro | Yes | Yes | | `APP_WATCH_ULTRA` | Apple Watch Ultra | Yes | No | | `APP_WATCH_SERIES_10` | Apple Watch Series 10 | Yes | No | | `APP_WATCH_SERIES_7` | Apple Watch Series 7 | Yes | No | | `APP_WATCH_SERIES_4` | Apple Watch Series 4 | Yes | No | | `APP_WATCH_SERIES_3` | Apple Watch Series 3 | Yes | No | | `IMESSAGE_APP_IPHONE_67` | iMessage iPhone 6.7" | Yes | No | | `IMESSAGE_APP_IPHONE_61` | iMessage iPhone 6.1" | Yes | No | | `IMESSAGE_APP_IPHONE_65` | iMessage iPhone 6.5" | Yes | No | | `IMESSAGE_APP_IPHONE_58` | iMessage iPhone 5.8" | Yes | No | | `IMESSAGE_APP_IPHONE_55` | iMessage iPhone 5.5" | Yes | No | | `IMESSAGE_APP_IPHONE_47` | iMessage iPhone 4.7" | Yes | No | | `IMESSAGE_APP_IPHONE_40` | iMessage iPhone 4" | Yes | No | | `IMESSAGE_APP_IPAD_PRO_3GEN_129` | iMessage iPad Pro 12.9" (3rd gen+) | Yes | No | | `IMESSAGE_APP_IPAD_PRO_3GEN_11` | iMessage iPad Pro 11" | Yes | No | | `IMESSAGE_APP_IPAD_PRO_129` | iMessage iPad Pro 12.9" (1st/2nd gen) | Yes | No | | `IMESSAGE_APP_IPAD_105` | iMessage iPad 10.5" | Yes | No | | `IMESSAGE_APP_IPAD_97` | iMessage iPad 9.7" | Yes | No | > **Note:** Watch and iMessage display types support screenshots only -- video files in those folders are skipped with a warning. The `--replace` flag deletes all existing assets in each matching set before uploading new ones. > > `download-media` saves files in this same folder structure (defaults to `-media/`), so you can download, edit, and re-upload. #### Verify and retry stuck media Sometimes screenshots or previews get stuck in "processing" after upload. Use `verify-media` to check the status of all media at once and optionally retry stuck items: ```bash # Check status of all screenshots and previews asc-client apps verify-media # Check a specific version asc-client apps verify-media --version 2.1.0 # Retry stuck items using local files from the media folder asc-client apps verify-media --folder media/ ``` Without `--folder`, the command shows a read-only status report. Sets where all items are complete show a compact one-liner; sets with stuck items expand to show each file and its state. With `--folder`, it prompts to retry stuck items by deleting them and re-uploading from the matching local files, preserving the original position order. ### Builds ```bash # List all builds asc-client builds list asc-client builds list --bundle-id # Archive an Xcode project asc-client builds archive asc-client builds archive --scheme MyApp --output ./archives # Validate a build before uploading asc-client builds validate MyApp.ipa # Upload a build to App Store Connect asc-client builds upload MyApp.ipa ``` The `archive` command auto-detects the `.xcworkspace` or `.xcodeproj` in the current directory and resolves the scheme if only one exists. It accepts `.ipa`, `.pkg`, or `.xcarchive` files for `upload` and `validate`. When given an `.xcarchive`, it automatically exports to `.ipa` before uploading. ### Workflows Chain multiple commands into a single automated run with a workflow file: ```bash asc-client run-workflow release.txt asc-client run-workflow release.txt --yes # skip all prompts (CI/CD) ``` A workflow file is a plain text file with one command per line (without the `asc-client` prefix). Lines starting with `#` are comments, blank lines are ignored. **Example** -- `release.txt` for submitting version 2.1.0 of a sample app: ``` # Release workflow for MyApp v2.1.0 # Create the new version on App Store Connect apps create-version com.example.MyApp 2.1.0 # Build, validate, and upload builds archive --scheme MyApp builds validate --latest --bundle-id com.example.MyApp builds upload --latest --bundle-id com.example.MyApp # Update localizations and attach the build apps update-localizations com.example.MyApp --file localizations.json apps attach-latest-build com.example.MyApp # Submit for review apps submit-for-review com.example.MyApp ``` Without `--yes`, the workflow asks for confirmation before starting, and individual commands still prompt where they normally would (e.g., before submitting for review). With `--yes`, all prompts are skipped for fully unattended execution. ### Automation Most commands that prompt for confirmation support `--yes` / `-y` to skip prompts, making them suitable for CI/CD pipelines and scripts: ```bash asc-client apps attach-latest-build --yes asc-client apps submit-for-review --yes ``` ## Acknowledgments Built on top of [asc-swift](https://github.com/aaronsky/asc-swift) by Aaron Sky. Developed with [Claude Code](https://claude.ai/code). ## License MIT