From publish-mobile-app
Automate iOS App Store + Google Play Store publishing for Capacitor, Expo, or Flutter apps — listing copy, screenshots, IPA/AAB upload, reviewer credentials, and fixing common rejection emails (Guideline 2.3.8 metadata, 2.1 China license, 4.0 sign-in, etc). Use when user mentions `/publish-mobile-app`, Play Store, App Store Connect, fastlane, gradle-play-publisher, TestFlight, or pastes an Apple/Google store rejection email.
How this skill is triggered — by the user, by Claude, or both
Slash command
/publish-mobile-app:publish-mobile-appThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Automates the boring parts of shipping a mobile app to both stores. Forged from real production ship cycles: one-command listing sync, signed IPA upload to TestFlight, reviewer-user provisioning, and recipes for the most common rejection emails.
Automates the boring parts of shipping a mobile app to both stores. Forged from real production ship cycles: one-command listing sync, signed IPA upload to TestFlight, reviewer-user provisioning, and recipes for the most common rejection emails.
When invoked via /publish-mobile-app, route based on the user's argument:
| Argument | What it does |
|---|---|
setup | One-time wiring: fastlane + gradle-play-publisher + reviewer user + key bootstrap |
push | Upload current listing + screenshots to both stores (or one, ask user) |
ipa | Build signed iOS IPA and push to TestFlight |
aab | Build signed Android AAB and push to Play internal track |
release | Full bump + build + upload + listing push for both stores |
fix-rejection | User pastes rejection email; map issue → fix → apply |
status | Read live state from both stores via API; report what's present and what's missing |
checklist | Generate/refresh RELEASE_CHECKLIST.md at repo root |
If no argument given, ask the user which sub-command they want, defaulting to status to orient first.
Detect which mobile framework the project uses before doing anything else:
test -f capacitor.config.ts -o -f capacitor.config.json && echo capacitor
test -f app.json && grep -q '"expo"' app.json 2>/dev/null && echo expo
test -f pubspec.yaml && echo flutter
Behaviors differ per stack — see REFERENCE.md.
When user runs setup, work through this checklist in order. Mark each with TodoWrite and tick off as you go.
fastlane --version, gradle (Android), Xcode (iOS), bun or node.p8 key in App Store Connect → Users and Access → Integrations → App Store Connect APIASC_KEY_ID, ASC_ISSUER_ID, ASC_KEY_PATH to assemble ios/app-store-connect-key.json.p8 from ~/Downloads/ to ~/.appstoreconnect/private_keys/ (standard location)ios/fastlane/Appfile with app_identifier, team_idios/fastlane/Fastfile with lanes: metadata, screenshots, beta (build+TestFlight upload). Template: REFERENCE.md#fastfile-templateAPI_KEY_PATH = File.expand_path("../app-store-connect-key.json", __dir__) so it works from any CWDLANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 or Ruby crashes on em-dashes/bullets in description.txtios/fastlane/metadata/en-US/ with name.txt, subtitle.txt, description.txt, keywords.txt, promotional_text.txt, release_notes.txt, support_url.txt, privacy_url.txt, marketing_url.txtios/fastlane/metadata/copyright.txt (non-localized, top-level)ios/fastlane/screenshots/en-US/ — naming conventions matter for iPad routing, see REFERENCE.md#ipad-screenshot-filename-magicandroid/play-config.json (gitignored)android/app/build.gradle: see REFERENCE.md#android-build-gradletrack should be internal; defaultToAppBundles.set(true); releaseStatus.set(ReleaseStatus.DRAFT) until first prod releaseandroid/app/src/main/play/listings/<locale>/ — locale must match Play Console default (often en-GB, not en-US!)graphics/icon/icon.png (512×512), graphics/feature-graphic/feature-graphic.png (1024×500), graphics/phone-screenshots/, graphics/tablet-7-inch-screenshots/, graphics/tablet-10-inch-screenshots/release-notes/<locale>/default.txtios/app-store-connect-key.json, *.p8, android/play-config.json, ios/.env.review, ios/build/, ios/*.ipa, ios/fastlane/README.mdios/.env.review. Falls back to printing instructions if not Supabase.+91XXXXXXXXXX format, no spaces)app_review_information: blockWhen user runs push:
kids/children in subtitle if not in Kids Category (Apple flags this — Guideline 2.3.8)cd ios && LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 fastlane metadatacd android && ./gradlew publishListingWhen user pastes a rejection email, parse the Guideline number and route to the appropriate recipe. Full recipes in REJECTIONS.md.
| Apple Guideline | Common cause | Quick fix |
|---|---|---|
| 2.1 | China book/magazine license missing | Remove China mainland in App Store Connect → Pricing & Availability |
| 2.3.8 | Subtitle/keywords imply "for kids" without Kids Category | Scrub kids/children from subtitle + keywords + promo; keep age messaging in description (it's allowed) |
| 2.3.10 | Inaccurate marketing copy | Re-read description vs actual app behavior |
| 4.0 | Reviewer sign-in failed | Re-run reviewer-user script to rotate password; update App Review Information |
| 5.1.1 | Privacy / data collection | Check App Privacy questionnaire — must match what app actually collects |
| Google Play | Common cause | Quick fix |
|---|---|---|
| Data Safety mismatch | Declared data types don't match runtime | Update Data Safety form in Play Console |
| Account deletion URL missing | Required since Play Console 2024 | Add /delete-account page + URL in Data Safety form |
| Target audience violation | App targeting children without Designed for Families opt-in | Either change target age range or join Designed for Families |
These have no public API and must be done in the store consoles:
deliver), Export Compliance (one-time ITSAppUsesNonExemptEncryption plist flag handles this for most apps)See MANUAL_FORMS.md for guided answers — what to pick for each question for a typical content-creation app.
.p8 + IDsFastlane's "Successfully uploaded" log ≠ "appears correctly in App Store Connect UI". Always verify via the App Store Connect API after any push. The check-ios-state.ts script is the source of truth — fastlane sometimes routes 2048×2732 iPad screenshots to the wrong display-type slot.
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
npx claudepluginhub logesh-kumar/publish-mobile-app --plugin publish-mobile-app