20 KiB
20 KiB
Commands
Every write command takes --dry; re-runs are idempotent; output is one timestamped line per step, so long jobs can
run in the background with a log (storebound shots render > .storebound/render.log 2>&1 &).
Setup and checks
| command | kind | what |
|---|---|---|
init [--profile app|game|subscription-app] |
local | copy the templates of a profile (default app), gitignore .storebound/ |
import fastlane [--dir fastlane] [--profile ...] |
local | config, store/appstore.md, store/listing.md and screenshot frames from a fastlane setup; never overwrites, reports what is not mapped |
install --agent <tool> |
local | skills + MCP entry for an AI tool |
mcp |
local | stdio MCP server wrapping the commands |
serve --stdio |
local | JSON-RPC session for the storebound desktop app (see Desktop machine interface) |
inspect [--json] |
local | offline summary of the config: name, store ids, languages, products |
check |
local | config, copy limits, data safety, products, subscriptions, profile (delete-account URL, demo account, terms URL), files; warns on untranslated release notes |
catalog diff [--store] [--threshold 10] |
API, read-only | one catalog vs both stores: missing / extra / mismatched products and subscriptions, US and override prices, locales, offers, per-region price differences between the stores; exit 1 on mismatches |
check --aso |
local | keyword audit: App Store keyword field rules, Play stuffing / claims |
scan [--store apple|play] [--json] [--write] [--originality --against <folders>] |
local, read-only | rejection risks in the project itself (stack, SDKs, Info.plist, manifest, listings) with guideline, evidence file:line, fix and skill; Data safety / App Privacy / ATT / privacy manifest proposal as a diff (--write adds the detected answers to the config); exit 1 on blockers |
validate [--apple] [--play] |
API, read-only | readiness report with ordered blockers plus the local renders checks (--no-local skips); exit 1 while any blocker is left |
originality --against <folders> [--json] |
local, read-only | Guideline 4.3 check vs your other apps: name, listing text, icon and screenshot perceptual hashes, project structure; scores, near-duplicate flags, suggestions; exit 1 when flagged |
whats-new [--since <tag>] |
local | draft player-facing release notes from git log into both listing files |
whats-new --languages en,de,tr / check / apply |
local | one file per language (store/whats-new/) for your agent (or a --translate hook of yours) to translate, per-store limits (Play 500, App Store 4000), then into both listing files |
listing translate --to de,ja [--from en] [--translate "<cmd>"] |
local | per-language listing sections in both listing files (App Store name, subtitle, promotional text, keywords, description; Play title, short, full) for your agent (or a hook) to translate, marked as drafts until reviewed; keywords cleaned up |
listing check / listing reviewed --lang <ids> |
local | every language section against the store limits and keyword rules, untranslated and unreviewed drafts (exit 1 on a problem) / remove the draft marker after a human read it |
flow list | validate | run <name> [NAME=value] [--dry | --apply [--yes]] [--from <step> | --resume] |
local + whatever the steps call | repo-local workflows (store/workflows/*.yml): steps in order with progress; writes run as dry runs unless --apply, owner steps are listed as your click and never run (see Repo-local workflows) |
onboard [--store] [--write] [--no-web] [--no-catalog] |
API, read-only + local | an app that is already live: products and subscriptions with their USD / base prices (catalog diff clean), contact e-mail, website, privacy / support URLs, App Review contact and demo account (.storebound/credentials.json, masked), sign-in for review (Apple review detail + code auth signals), the account deletion page on the app's site; then only the owner questions nothing proves. Never changes store prices |
catalog pull [--write] |
API, read-only + local | IAP and subscription texts on the stores vs the config: a proposal diff (.storebound/pull/catalog.json); the config is never rewritten |
ads scan --ios <path> |
local | AdAttributionKit / SKAdNetwork: ad network ids, postback copy endpoints, attribution windows and cooldown, conversion value updates; exit 1 on a blocker |
privacy-manifest --ios <path> |
local | PrivacyInfo.xcprivacy, required-reason APIs, SDKs without manifests |
api list | coverage | apple|play <operation> |
API | every App Store Connect / Google Play operation (see Every endpoint); GET runs, writes are dry unless --yes in a terminal |
desktop [--yes] [--dry] [--download] |
local + download | the desktop app of this CLI's version, opened on this folder: installs it for this user when missing (size, SHA-256 and signature checked; asks once, --yes), updates an older one, notes a newer one (--force to downgrade); --download only saves the checked installer |
accounts [list] | import [--dry] | use <profile> | default <profile> |
local | the store accounts of this machine (~/.storebound/credentials, shared with the desktop app); import moves a project's store keys into a profile (same key = same profile), never prints values; default sets the machine default profile (env > a profile the project names > the project's own keys > this default > the only profile) |
apps folders | add [<folder>] | remove <folder> |
local | the app folders of this machine (~/.storebound/projects.json), the same list as the desktop app |
doctor [--json] |
local | which local tools are here (ffmpeg, Chrome, playwright, Xcode, adb, git) and how to install the missing ones |
icons |
local | App Store 1024 (no alpha), Play 512, web, Capacitor sources, Android legacy launcher icons |
Google Play
| command | kind | what |
|---|---|---|
play listing [--include-drafts] |
API | app details, title / short / full description per language, promo video URL (play.video); prints the plan first (old -> new per field, draft languages skipped), --dry stops there, the real run asks and sends only changes |
play listing pull [--write] |
API, read-only + local | live listings back into store/listing.md: diff first, writes only with --write |
play images [--variant b] |
API | icon, feature graphic, phone / 7" / 10" screenshots, one edit per language |
play products |
API | one-time products: regional prices from convertRegionPrices + your overrides, activate |
play subscriptions [--csv] |
API | subscriptions: listings + benefits, one auto-renewing base plan, regional prices, intro and extra offers, activate (plan first, asks) |
play data-safety |
API | Data safety form (CSV import); --csv writes the file |
play build [--version-code N] [--flavor f] |
local + API read | build.prebuild first (Capacitor: web build + cap sync; stale copied web assets stop the build), then Gradle bundleRelease (Flutter flutter build appbundle; Capacitor, React Native, Unity export found) with the next free versionCode and the upload key from env / .storebound (passed through the environment, never argv); AAB checked and copied to build/android/ |
play upload [<aab>] --track internal|alpha|beta |
API | AAB to a testing track with release notes; versionCode checked first; --dry is read-only, a real run asks |
play release <aab> |
API | upload + tracks (--internal completed --production draft, --production inProgress --fraction 0.05), release notes |
play rollout |
API | --fraction x, --halt, --resume, --complete (asks first, except halt) |
play next-version-code |
API, read-only | next free versionCode |
play status |
API, read-only | tracks, listings, products |
App Store
| command | kind | what |
|---|---|---|
apple bundle |
API | register the bundle id, find the app record |
apple listing --version x.y.z [--build N] [--include-drafts] |
API | prints the plan first (version: keep / update / create / refuse with the reason; per locale create / update, old -> new per field; draft locales skipped), --dry stops there, the real run asks and applies exactly it: version (manual release), the build with exactly that number, texts per locale (name: the locale's ### name, else apple.name, else app.name) |
apple listing pull [--version x.y.z] [--write] |
API, read-only + local | live texts back into store/appstore.md: diff first, writes only with --write |
apple screenshots [--variant b] |
API | 6.9" + 6.5" (+ 13" iPad with apple.ipad, + 6.3" with apple.iphoneMedium) per locale, MD5-idempotent |
apple previews [--poster 5] |
API | app preview videos per locale, checked first, MD5-idempotent, poster frame |
apple iap / apple iap-review |
API | IAPs (consumable, non-consumable, non-renewing), localizations, price schedules, availability / review screenshots |
apple iap-submit [--with-version] [--resolve-iaps] [--no-submit] |
API | IAP / subscription / group versions into a review submission (the first of a type together with the app version); reuses the open submission (a draft, or one back from review with UNRESOLVED_ISSUES; --resolve-iaps marks its REJECTED IAP items resolved), never a second one; asks before adding and before submitting |
apple submit --build <n> [--version x.y.z] |
API | a version to App Review: build n (by number, VALID) attached, the open review submission reused (a new draft only when none is open), the ready IAPs / subscriptions with it, submitted with the same retry as resubmit; plan table without --yes (the owner's step; the desktop's Submit for review) |
apple resubmit --build <n> [--resolve-iaps] |
API | after a rejection: attaches build n to the rejected version, reuses the UNRESOLVED_ISSUES submission, adds missing items, marks the REJECTED version item resolved (IAP items with --resolve-iaps) and resubmits (a REJECTED item left stops it at once; retried while Apple says "not ready yet" only when none is left); plan table without --yes |
apple offer-codes [--codes] |
API | offer code campaigns for one-time purchases; custom and one-time-use codes only with --codes (asks; codes saved to .storebound/offer-codes/) |
apple win-back |
API | win-back offers for lapsed subscribers (asks: they go live on their start date) |
apple promoted [--enable] |
API | promoted in-app purchases: create (disabled), order, switch on (asks) |
apple preorder status | enable --release-date | end |
API | pre-orders per territory (enable / end ask first) |
apple cpp list | create | upload | submit | visible |
API | custom product pages from the config and a shots variant; submit / visible ask first |
apple events list | create | upload | submit |
API | in-app events with schedule, localizations, card and details images; submit asks first |
apple subscriptions [--csv] [--codes] |
API | groups, subscriptions, levels, localizations, availability, equalized prices + overrides + CSV (scheduled changes), introductory and promotional offers, offer code campaigns, review screenshots (plan first, asks; custom codes only with --codes) |
apple appinfo |
API | categories, age rating, content rights, Free, territories; plan first (old -> new), only changes are sent |
apple review-details |
API | App Review contact, demo account (from .storebound/, masked), notes (+ sign-in steps, where account deletion is) |
apple encryption |
API | export compliance answer from apple.usesNonExemptEncryption (never guessed) |
apple release --phased on|pause|resume|complete, --manual-release |
API | phased release, release an approved version (resume / complete / release ask first) |
apple signing status |
API, read-only | bundle id capabilities, distribution certificates (with / without a private key on this Mac), App Store profiles per bundle id, installed or not |
apple signing ensure [--keychain] [--no-install] |
API | missing capabilities, a distribution certificate from a key made here (kept 0600 in .storebound/signing/, never printed), App Store profiles installed for Xcode; dry first, asks; Developer ID needs the Account Holder (403 explained) |
apple build [--version x.y.z] [--build-number N] |
local + API read | build.prebuild first (Capacitor: web build + cap sync; stale copied web assets stop the build), then xcodebuild archive + exportArchive with a generated ExportOptions.plist (app-store-connect, team, signing style, profiles) and the API key; next build number; Capacitor, React Native, Flutter, Unity projects found |
apple upload [<ipa>] [--via api|altool] |
API | IPA through the App Store Connect API build upload (or altool), build number checked, waits until VALID (exit 0 / 1 / 7); dry first, asks |
apple next-build |
API, read-only | next safe build number |
apple status |
API | versions, builds, IAPs, submissions; --wait-review (exit 0 / 1 / 7); --cancel-submission <id> |
apple ppo status | create --variant b | upload --variant b |
API | Product Page Optimization test from shots variants: treatments, localizations, screenshot sets |
apple ppo start | stop |
API | start / stop the test (asks first; a stopped test cannot be restarted) |
TestFlight
| command | kind | what |
|---|---|---|
apple testflight status |
API, read-only | groups, testers and builds per group, recent builds with internal / external beta states |
apple testflight groups [sync] |
API | list the groups (read-only); sync creates the ones of apple.testflight.groups that are missing |
apple testflight testers [--csv f] [--remove] [--invite] |
API | testers from a CSV in .storebound/ into their groups (asks first; emails masked) |
apple testflight what-to-test --build N |
API | "What to Test" per locale from store/appstore.md (whatToTest, else whatsNew) |
apple testflight info |
API | Beta App Description, feedback email, URLs, Beta App Review contact and notes |
apple testflight distribute --build N --group a,b [--submit-review] |
API | the build to groups; external groups and Beta App Review ask first |
apple testflight wait --build N [--timeout 60m] |
API, read-only | until processing ends, with progress; exit 0 VALID / 1 FAILED / 7 timeout |
apple testflight expire --keep N | --older-than D |
API | expire old builds (never attached or processing ones); dry run, then asks |
After launch
| command | kind | what |
|---|---|---|
health [--weekly] [--days 7] |
API, read-only | Play vitals (user-perceived crash / ANR vs 1.09 % / 0.47 %, devices, top issues), App Store metrics, diagnostics, TestFlight crashes; --weekly writes a Markdown report |
reviews list [--unanswered] |
API, read-only | recent reviews of both stores |
reviews draft |
API + local | one reply draft per unanswered review in .storebound/replies/ |
reviews send |
API | sends drafts with approved: true (checks length and incentives, asks first) |
prices export [--no-subscriptions] |
API + local | current prices of every product and subscription (Apple current + scheduled, Play base plan regions), both stores, as store/prices.csv; subscription rows feed apple subscriptions --csv / play subscriptions --csv |
prices import [--reconvert] |
API | diff table, then (asks first) Apple price schedules incl. future-dated changes and Play regional prices |
analytics setup |
API | App Store analytics report request (once, Admin key) |
analytics snapshot [--days 28] |
API + local | impressions, page views, downloads (App Store), visitors, acquisitions, installs (Play reports bucket) -> .storebound/analytics/ |
analytics compare |
local | snapshots vs the git history of the store files: before / after each listing change |
reports apple-sales | apple-finance | play-earnings | play-sales |
API, read-only + local | sales / finance reports into .storebound/reports/, summary per product and currency, CSV export |
triage [--days 14] |
API, read-only | TestFlight crash and screenshot feedback, Play error reports: grouped by signature with devices, OS versions, builds |
aso rank [--storefronts us,de] |
network + local | App Store rank per keyword and storefront plus competitors from the public iTunes Search API (rate limited) -> .storebound/aso/ |
aso competitors [--term <kw>] [--storefront us,tr] [--top 10] |
network + local | top apps per keyword (name, developer, rating count, first release, last update, localized genre; no subtitles: not in any public API) and the words in their names you do not cover, same rate limit -> .storebound/aso/competitors/ |
aso suggest [--locale en-US] [--write] |
local (+ Apple Ads API with credentials) | keyword candidates (own text, competitor names, localized category names, Apple Ads keyword suggestions with their relative 0-100 popularity) scored by relevance and competition, and a 100-byte keyword field per locale as a diff; --write puts it into store/appstore.md as a draft for review. Popularity is never estimated |
aso audit |
local | one report: check --aso, free keyword room, rank trend arrows, competitor gaps, Play short description and density, App Store conversion from the analytics snapshots, PPO / Play experiment ideas and the next 3 actions |
Screenshots and video
| command | kind | what |
|---|---|---|
shots capture [--source web|ios-sim|android-emu|folder] [--concurrency N] [--only-missing | --force] |
local | raw frames from your running app or game; web: parallel contexts, optional one boot per language (capture.session), skips unchanged frames, timing per step |
shots fonts |
network | font subsets for your copy (Noto for CJK / Arabic / Cyrillic / Devanagari ...), your own local font files, and the glyph coverage check per language |
shots render [--variant b | --variants] [--concurrency N] |
local | every store size and language in the game or app style, feature graphic, contact sheet, overflow report |
shots jpeg |
local | JPEG q92 copies of the Play renders (about 4x faster uploads) |
shots check [--variants] [--json] |
local, read-only | store rules: sizes, alpha, format, bytes, counts, overflow, fallback / missing glyphs, videos, folder frames |
shots gallery |
local | <renders>/index.html review page |
shots record [--source ...] |
local | app or gameplay clips: web (Chromium screencast), simulator, emulator, folder |
shots video [--target iphone,ipad,youtube] |
local | app previews + promo video with captions, poster, checks |
Many apps and release trains
| command | kind | what |
|---|---|---|
ws init |
local | find the app folders below and write storebound.workspace.json (globs like games/*) |
ws list [--all] |
local | apps (folders + store-only apps), studios, accounts and whether each credential profile has its keys |
ws status [--offline] [--apps a,b] |
API, read-only | portfolio table: every app x both stores (live / rollout % / next version), catalog parity, check; parallel |
ws check, ws validate [--apps a,b] |
local / API, read-only | the offline check / the readiness report of every app in one table |
ws run <command> --apps a,b | --all [--apply] |
per command | any read command in every app; writes as dry runs unless --apply; never submit / release / rollout / send |
ws apps import --account <profile> |
API, read-only + local cache | the apps a store account sees, paired with the folders (the desktop's rules) |
ws desktop export [--out f | --merge [--apply]], ws desktop import |
local | the workspace to and from the desktop app's state (labels, never keys) |
release status [--app a,b] [--versions] |
API, read-only | both stores on one train per version: build > testing > review > live > rollout % |
release plan <version> [--app a] |
API, read-only | what is left for that version on each store, in fix order, with the owner's next step |