storebound/skills/store-preflight/SKILL.md

10 KiB

name description
store-preflight Run and read the storebound readiness checks before submitting a mobile app or game - `storebound scan` (offline rejection-risk scan of the project files, SDKs and listings with guideline, evidence and fix), `storebound check` (offline config, copy limits, files), `storebound check --aso`, `storebound validate` (read-only App Store Connect + Google Play report with ordered blockers) and `storebound privacy-manifest`. Use before every submission, when the user asks "is my app ready to submit", or after changing listings, builds, IAPs or SDKs.

Store preflight

CLI: storebound (or the MCP tools scan, check, check_aso, validate, privacy_manifest). All are read-only on the stores; run them freely.

Order

  1. storebound scan: reads the project itself (Xcode project, Info.plist, entitlements, privacy manifest, Podfile.lock / Package.resolved, Gradle, AndroidManifest.xml, package.json / app.json / capacitor.config, pubspec, Unity and Godot settings, Unity ProjectVersion.txt, CMake / ndk-build files, res/xml and strings.xml, and the merged manifest under build/intermediates when the project was built locally) and the listing files. Prints the stack, the SDKs (version, file:line) and every rejection risk with guideline, evidence, fix, severity (BLOCKER, HIGH, MEDIUM, low) and the skill to open; then the Data safety / App Privacy / ATT / privacy manifest proposal, each item "detected (file:line)" or "ask owner", as a diff against the config. Exit 1 on an open blocker. --write adds only the detected answers to the config (show the diff and ask the owner first; MCP never writes). --store apple|play, --json. A finding the owner accepts goes into scan.ignore: [{ rule, reason, match?, evidence? }] (match = text in the finding title, to accept one check of a rule with several; evidence = text in one evidence line, e.g. src/main.ts:12); never add one without the owner's reason. scan and check name an entry that matches no finding. The Play rules also read play.targetAges (Families), play.accountType / play.accountCreated (closed-testing requirement) and play.billingPrograms (payments): ask the owner for them, never guess.
  2. storebound check: config, both listing files (limits are checked locally: title 30, subtitle 30, keywords 100 bytes, Play short 80, notes 500 ...), screenshot copy, Data safety answers, IAP texts (Apple description 45), files the config points at, .storebound/ gitignored, and the app profile: accounts need accounts.deletionUrl (+ inApp), a sign-in for review needs the demo account in .storebound/, subscriptions need app.termsUrl. Fix everything it lists; it exits 1 on problems.
  3. storebound check --aso: keyword field use, repeats, stuffing (aso-basics). Errors exit 1, warnings are advice.
  4. storebound privacy-manifest --ios ios/App (iOS): app manifest, required-reason APIs, SDKs without manifests (privacy-manifest skill).
  5. storebound validate (or --apple / --play): talks to both APIs read-only and prints findings in fix order, plus the open scan findings (codes scan-<rule>; --no-scan skips). Exit 1 while there is a blocker. --json.
  6. With in-app products or subscriptions: storebound catalog diff (read-only): both stores against the config, prices per region, offers. Exit 1 on missing or mismatched items.
  7. One list for the version you ship: storebound release plan <version> (MCP release_plan, read-only) puts the check problems, the version's state on each store and the validate blockers in fix order, then names the owner's next step (submit, promote, release). Report it as it is; the owner does the owner steps.

Many apps (a storebound.workspace.json above the app folders, storebound ws init writes it): storebound ws check and storebound ws validate [--apps a,b] run the same checks over every app, a few at a time, each with its studio's credential profile; storebound ws run <command> --apps a,b runs any other read command (writes only as dry runs).

Share the report: storebound report

For the owner, a teammate or a client who should not need a terminal: storebound report runs scan, check and validate (read-only; a store without credentials shows "Not checked" with the reason) and writes one self-contained page, .storebound/reports/readiness-<date>.html, then opens it in the browser. A verdict per store, every finding with its fix and console link, and the questions only the owner can answer. Secrets are masked. --md for Markdown, --json for the data, --no-open in scripts. MCP: report; desktop: Checks > Report.

Reading scan

finding fix skill
2.1(a) sign-in but no demo account demo account in .storebound/credentials.json, apple review-details review-access
5.1.1(v) / Play account deletion in-app delete + accounts.inApp, a web page in accounts.deletionUrl account-deletion
4.8 Google / Facebook login without Sign in with Apple add Sign in with Apple (or an equivalent private login) review-rejections
3.1.1 no Restore Purchases / outside payment a visible restore button; digital goods through IAP store-iap-setup
3.1.2(c) subscription info app.termsUrl, Terms + renewal wording in the description, links in the app store-subscriptions
5.1.2(i) ATT NSUserTrackingUsageDescription + the prompt before SDKs start, or no tracking ads-mediation-checks
5.1.1(ii) purpose strings a specific sentence per used permission review-rejections
privacy manifest (ITMS-91053 / 91061) PrivacyInfo.xcprivacy with reasons; update old SDKs privacy-manifest
2.3.10 / 2.3.7 / 2.1(a) metadata no other platforms, competitor names, prices or template text aso-basics
export compliance ask the owner export-compliance
Play target SDK, foreground services, exact alarm, QUERY_ALL_PACKAGES, SMS / call log manifest / Gradle changes + declarations play-first-release
Play background location, photo / video, All files access, AccessibilityService, install packages, Health Connect, full-screen intent, VpnService remove the permission (tools:node="remove" when an SDK adds it) or fill its App content declaration with a video store-declarations
Play prominent disclosure / privacy policy in the app a disclosure right before the prompt that names the data and its use; the policy linked inside the app store-declarations, privacy-policy
Play Families / advertising ID certified ad SDKs only, no AD_ID or location in child-only apps; AD_ID declared on targetSdk 33+ ads-mediation-checks, store-declarations
Play 16 KB page sizes newer Unity / React Native / NDK r28+ / AGP 8.5.1+, check prebuilt .so files play-first-release
Play testing for new personal accounts closed test, 12 testers for 14 days, then apply for production play-first-release
Play metadata / impersonation title 30, no emoji, caps, claims, keyword repetition, other brands aso-basics
Play ads at launch / payments interstitials only at natural breaks; digital goods through Play Billing or play.billingPrograms ads-mediation-checks, store-iap-setup
privacy labels vs SDKs scan --write after the owner agrees, then App Privacy / play data-safety store-declarations

Reading validate

Each line: number, level (BLOCKER, warn, ok), store, message, and a fix: with the command or skill.

finding means fix
no build attached / build PROCESSING the version has no usable binary wait for VALID, then apple listing --version x --build N (explicit number)
export compliance not answered the build has no encryption answer export-compliance skill
<locale>: missing description / keywords / subtitle text not pushed for a locale edit store/appstore.md, apple listing
no APP_IPHONE_67 screenshots 6.9" set missing (required) apple screenshots; iPad apps add the 13" type to apple.screenshotTypes
review contact missing App Review information incomplete apple review-details
age rating unanswered new questions Apple added apple appinfo
no app price schedule / availability pricing never set apple appinfo; if the API refuses the first availability record, set it once in App Store Connect > Pricing and Availability
IAP MISSING_METADATA / no review screenshot product incomplete apple iap, apple iap-review
privacy policy HTTP 404 / unreachable URL broken privacy-policy skill
subscription MISSING_METADATA / no review screenshot / no group localization subscription incomplete apple subscriptions (store-subscriptions)
Play subscription base plan DRAFT not active play subscriptions
accounts.deletionUrl not set / unreachable Play needs a delete-account page account-deletion skill
sign-in required but no demo account App Review cannot get in (2.1) review-access skill, apple review-details
no Terms of Use URL / description without a Terms link subscriptions need the EULA link (3.1.2) store-subscriptions skill
Play <lang>: phoneScreenshots 1/2 graphics missing shots render, play images
app-ads.txt lacks lines / 404 ad networks cannot verify you ads-mediation-checks; the file lives at the root of the developer website
no release on any track nothing uploaded play release <aab>
product purchase option DRAFT not active play products
user-perceived crash / ANR rate over 1.09 % / 0.47 % (live apps) Play's bad behavior threshold is crossed store-health skill: storebound health, fix the top issues, ship a higher versionCode
Apple metric rated poor / heavy diagnostic signature hangs, launches, disk writes store-health skill (Xcode Organizer for the stack)

Vitals need the Play Developer Reporting API enabled for the service account; without it validate only notes "vitals not readable". --no-health skips these checks.

What validate cannot see (UI-only: check them yourself in the console with your browser tool)

App Privacy labels published, Play App content declarations (ads, target audience, content rating, advertising ID, App access with the demo account), in-app account deletion working, first subscriptions added to the version, agreements / tax / banking, countries for production on Play. (TestFlight groups and testers: storebound apple testflight status.) Fix what you can; tell the owner only what is an owner step (agreements, tax, banking).