storebound/docs/commands.md

23 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
edit --ops '<json>' [--dry] [--json] local edit the app folder's sources of truth: config values by path (comments and formatting kept), listing fields per store and language, the App Review contact; dry run with old -> new, the diff and the checks (store limits, keyword and metadata rules, the whole config validated); --show --json lists what the desktop editors show. Never commits
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
report [--out <file>] [--md] [--json] [--no-open] [--offline] local + API, read-only shareable store readiness report: scan, check and validate (only the stores whose credentials are there; otherwise each store says "Not checked" and why) in one self-contained HTML page .storebound/reports/readiness-<date>.html (inline CSS, no scripts, light / dark, print-friendly): a verdict per store, findings by store and severity with guideline, evidence, fix and console link, the questions only you can answer. Opens in the browser unless --no-open, --json, CI or no terminal; credentials, key ids, emails and the demo account are masked. --md writes Markdown, --json prints the data with the file path. Desktop: Checks > Report; MCP: report
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 games [status] API Play Games Services leaderboards and achievements from games (Games Configuration API; drafts, the owner publishes); the setup is console plan play-games-services; dry 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's "cannot be sent for review automatically" 400 is committed again with changesNotSentForReview=true (--not-sent-for-review from the start), then Send changes for review is the owner's
play rollout API --fraction x, --halt, --resume, --complete (asks first, except halt)
play next-version-code API, read-only next free versionCode
play status [--review-sent] API, read-only tracks, listings, products, changes storebound committed that wait for Send changes for review (local record; --review-sent forgets it)
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 game-center [status] API Game Center from games: the app's Game Center detail, the version switch, leaderboards and achievements with localizations (upsert by vendor id, read back; nothing submitted); dry first, asks
games status [--json] API, read-only Game Center and Play Games Services on both stores: capability, entitlement, games_APP_ID, counts vs the config, pending changes, console links
apple encryption API export compliance answer from apple.usesNonExemptEncryption (never guessed)
`apple release --phased on pause resume
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] [--store apple|play] [--json] [--no-write] API + local impressions, page views, downloads, App Usage (sessions, active devices, crashes) per day (App Store); visitors, acquisitions, daily user installs, active device installs, total user installs (Play reports bucket, also from env PLAY_REPORTS_BUCKET or the profile's reportsBucket) -> .storebound/analytics/; --json prints the snapshot on stdout; a store-only config needs apple.appId only
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; apple-sales and play-sales take --days N or --from/--to for a per-day JSON (daily summary, totals per currency, missing days)
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; signed-in apps: capture.auth (a sign-in request with ${cred:NAME} / ${env:NAME} references, or storageState)
shots login [--url <url>] [--timeout <s>] local opens a visible browser with a fresh profile; you sign in to a demo account by hand, Enter saves .storebound/auth.json (0600) for capture.auth.storageState; prints counts only
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 frames at device pixels), 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 %
status [--app <name, store id or folder>] [--json] API, read-only per platform: live and next version, build, track, review state, rollout % (docs/ship-step.md)
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

All docs · README