Open source · CLI · desktop app · for apps and games
From an empty folder to Submit for review.
On Google Play and the App Store. Your AI agent does all of it with storebound: builds, uploads, store text, screenshots in every language and size, in-app products and prices, the compliance forms, even the consoles without an API. You only press Submit.
npx storebound init
Needs Node 20+ (or Bun (opens in a new tab) 1.1+: bunx storebound init). No account, no sign-up, no telemetry.
- MIT licensed
- Zero runtime dependencies
- No telemetry
--dryon every write- 25 Agent Skills + MCP server
Works with Claude Code · Codex · Cursor · Gemini CLI · Copilot · Windsurf · OpenCode · or just the CLI
1 · The whole job
You ask once. Your agent does the rest.
“Get my app ready for both stores.” storebound plans every step on both stores in fix order, and your agent works through it: API first, its own browser for the consoles without an API, a dry run before every write, a read-back after.
$ storebound release plan 1.0.0
[release] Example App: validate (read-only, both stores)
Example App 1.0.0
both stores (fix first):
1. CONFIG App Review needs a demo account (sign-in required) · add reviewDemoAccount to .storebound/credentials.json · review-access skill
-> storebound check
2. CONFIG missing file: store/icon/icon.png
-> storebound check
3. CONFIG missing file: store/icon/foreground.png
-> storebound check
4. CONFIG missing file: store/icon/background.png
-> storebound check
App Store: not on the store
5. STORE 1.0.0 is not on App Store yet: upload a build (Xcode / Transporter), then create the version with its texts
-> storebound apple next-build; storebound apple listing --version 1.0.0 --build <N> --dry
6. BLOCKER no App Store version being prepared
-> storebound apple listing --version x.y.z
7. BLOCKER no build attached to the version
… 19 more steps on both stores, each with the command that fixes it
- Builds and uploadsSigning, the next free build number, AAB and IPA to the right track, TestFlight groups.
- Store text in every languageListings for both stores within every limit, translated drafts, What's new from git.
- Screenshots and previewsEvery store size, every language, from your real app, checked against both stores' specs.
- In-app products and pricesProducts and subscriptions on both stores from one list, priced in 175 countries.
- The compliance formsData safety, App Privacy, age rating, export compliance, answered from your config and code. What only you know, it asks once.
- Even consoles without an APIA
console plangives the agent the steps, the answers and the buttons it must never press.
Real output from the demo projects
Store screenshots, every size, every language
One command rendered 200 store-ready images: 6 device sizes plus the Play feature graphic, 4 languages, an A/B variant. Then checked them against both stores' specs: 0 errors.
$ storebound shots render --variants
EN
JA
AR
TR
EN
JA
AR
TR
EN
JA
AR
TR
EN
JA
AR
TR
200 images · iPhone 6.9" and 6.5", iPad 13", Play phone, 7" and 10" tablet, feature graphic
By hand 200 exports from a design tool, each dropped into the right slot in two consoles.
Catches what gets you rejected, before you upload
Checked a sign-in app against 7 store requirements, offline. 3 would have stopped it, each named with its fix. Fixed, re-checked: all 7 pass.
- Play listingtitle 30 · short 80 · full 4000store/listing.md is missing · fix:
storebound init2 languages, every field within limits fixed by init - App Store listingname · subtitle · keywords 100store/appstore.md is missing · fix:
storebound init2 locales, every field within limits fixed by init - Screenshot captionsevery scene, every language2 languages × 4 scenes, none missing
- Play Data safetythe form Play requires764 answers built from the config
- Account deletionPlay web page · Apple 5.1.1(v)web page and in-app path both set
- App Review sign-inApple 2.1 · Play App accesssign-in required, no demo account · fix: add it to
.storebound/demo account set, kept only in .storebound/ fixed by you - Secrets stay out of gitstore keys, demo account.storebound/ is in .gitignore
- In-app products, subscriptionsprice texts, terms URLnone in this app, skipped
Without it a missing demo account comes back as a Guideline 2.1 rejection.
Store forms answered from your config
Play's Data safety form: 764 answers derived from 12 lines of config, as the CSV Play imports. What only you can know, like encryption, it asks you. It never guesses.
$ storebound play data-safety --dry
[play] data safety: 4 data types declared (PSL_EMAIL, PSL_USER_ACCOUNT, PSL_USER_GENERATED_CONTENT, PSL_CRASH_LOGS)
764 answers · from 12 lines of config
$ storebound apple encryption --dry
error: apple.usesNonExemptEncryption is not set in storebound.config.ts. Decide it with the export-compliance skill (…); storebound never guesses it.
By hand Play's form, question by question, for every data type you collect.
examples/demo-game and demo-app · offline commands and dry runs, nothing sent to a storeStore art, every size, every language
shots render, checked by shots check.The consoles, too
$ storebound console plan play-content-rating
Play Console: Content rating (IARC)
Owner batch (everything the owner does, in ONE message, in the order the agent needs it):
1. [before the run] Answer 17 question(s) in ONE batch (askOwner), then write the answers into storebound.config.ts and rerun the plan: Category; V…
2. [before the run] Tick the IARC Terms of Use box @ Play Console > the app > Policy and programs > App content > Content ratings > "Start questio…
3. [after the run] Press Send changes for review once every App content card and store setting is done @ Publishing overview (left menu): "Submit…
start: https://play.google.com/console
then: Pick the developer account if asked (set play.developerId for a deep link)
then: the app (com.example.prismpuddle) in the app list
then: Policy and programs > App content
then: Content rating > Start (or Manage)
Steps:
2. Page 1: type the email address and pick the category (material radio: JS click on the inner [role=radio]). The IARC Terms of Use checkbox is an…
9. Summary: read the ratings per authority, then press its Save yourself (a declaration save, "Save", not "Submit"; verified 2026-10-13: it stores…
Never press: "IARC Terms of Use box", "Send changes for review", "Publish", "Submit", "Create", "Create app", "Send", "Release", "Definitions and Examples", "?", "More information", "Submit N changes for review", "Restart review"
Final button (the owner's): Send changes for review
… the answer sheet, the in-page helper and how to verify
Some store pages have no API: creating the app records, Play's App content cards and content rating, App Privacy labels. storebound console plan hands your agent the start URL, every step, the answer sheet from your config and the buttons it must never press. The agent drives the page and stops before the final button.
- App Store: Submit for Review · Play: Send changes for review
- Releasing an approved version, completing a rollout
- App Privacy Publish, agreements, banking and tax
- The answers only you can know, asked once, in one batch
Every step, what is API, what the agent drives and what stays yours: the journey (opens in a new tab).
2 · No avoidable rejections
You won't get rejected for the avoidable things.
storebound scan reads your project offline and read-only: Xcode and Gradle files, Info.plist, manifests, entitlements, lockfiles and engine settings, plus your config and listings. It works out the stack and the SDKs, then reports every rejection risk it can prove, each with the guideline, the evidence as file:line, the fix, a severity and the skill to open.
$ storebound scan
Rejection risks: 2 blocker, 3 high, 0 medium, 0 low
1. BLOCKER 2.1(a) · App Store · Sign-in is required but there is no demo account for App Review
at storebound.config.ts:12 reviewAccess: { signInRequired: true, instructions: 'Sign in with the demo account.' },
at storebound.config.ts:11 accounts: { enabled: true },
at Podfile.lock:3 Google Sign-In: GoogleSignIn 7.1.0
fix: Create a demo account that sees every feature (not a sign-up the reviewer must do), put it in .storebound/credentials.json as reviewDemoAccount (never in the repo), then `storebound apple review-details`.
skill: review-access · https://developer.apple.com/app-store/review/guidelines/
2. BLOCKER 5.1.1(v) · App Store · Accounts can be created but no in-app account deletion was found
at storebound.config.ts:11 accounts: { enabled: true },
at Planner/LoginView.swift:11 Button("Create account") { Task { try await AccountApi.signUp() } }
at Planner/LoginView.swift:17 static func signUp() async throws {
fix: Add "Delete account" in the app (it deletes the account and its data, not only signs out; with Sign in with Apple also revoke the token), then set accounts.inApp to where it starts, e.g. "Settings > Account > Delete account".
… 3 more findings (4.8, 3.1.1, 5.1.2(i)), then the Data safety / App Privacy proposal
What it proves, on both stores
- 2.1(a)App access
A sign-in with no demo account for the reviewer.
- 5.1.1(v)Account deletion
Sign-up or social login without an in-app deletion path or a deletion URL.
- 4.8
Google or Facebook login without Sign in with Apple or another equivalent option.
- 3.1.1, 3.1.2Payments
No Restore Purchases path, card SDKs next to in-app products, missing subscription terms.
- 5.1.2Data safety
Tracking SDKs without ATT; SDK data types missing from App Privacy or Data safety.
- 5.1.1, ITMS-91053
Permissions without purpose strings; a missing or incomplete privacy manifest.
- Restricted permissions
Background location, photos, all files, accessibility, exact alarms, foreground services, and the Console declaration each one needs.
- 1.3Families
Ad or analytics SDKs in a Kids Category or child-directed app.
- Target API, 16 KB pages
targetSdk below 36; Unity, React Native, NDK or AGP versions without 16 KB page support.
- 2.3.7, 2.3.10Metadata
Other apps' names, "best / #1", keyword lists, other stores in App Store text, placeholder text.
- 2.2
"Beta", "demo" or "test" wording in the app name and the listing.
- 4.3Repetitive content
scan --originality --against <folders>adds the near-duplicate check against your other apps.
- 4.8 App Store guideline
- Families Google Play policy
Below the risks comes a proposal for Data safety, App Privacy, ATT and the privacy manifest from the detected SDKs, each answer marked detected or ask owner. Nothing is written unless you run scan --write. validate includes the open findings, and the desktop app shows them on its Checks tab.
3 · The desktop app
Every app on both stores, in one window.
Releases, charts, catalog and prices side by side, crash health, reviews, TestFlight and the rejection checks, for every app and game you ship. Send for review from there too: a dry run first, then a confirm. Same storebound underneath, with the CLI's version number, store accounts and app folders: npx storebound desktop installs it and opens your app folder.
Download storebound desktop
macOS, Windows and Linux. Looking up the latest release…
- macOS11+, Apple silicon and Intel · .dmg
- Windows10 / 11 · x64 installer
- Linuxx64 AppImage
- Debian / Ubuntux64 .deb
Checksums and signatures
| System | File | SHA-256 |
|---|
- Checksum:
shasum -a 256 <file>(macOS, Linux) orGet-FileHash <file>(Windows) must print the SHA-256 above. - Signature: every file has a
.signext to it (the app's update key, minisign). With minisign (opens in a new tab):base64 -d <file>.sig > f.minisig && minisign -Vm <file> -x f.minisig -P <key>, with the public keyRWQqOO/ZeIr3RBmolt/fx108m89QNEUndRTFrucjx0CBMoeFb7/xhrvW - Or let the CLI do both:
npx storebound desktopdownloads the app for your system, checks its size, SHA-256 and signature, installs it for your user (no admin rights; it asks first) and opens it on the current app folder.--downloadonly saves the checked installer to ~/Downloads.
One product, one version: the app and the npm package storebound (CLI, MCP server, agent skills) are released together with the same number, and the app runs its own copy of that CLI. They share the store accounts (~/.storebound/credentials) and the list of app folders. The app also updates itself from this site: each update is signed, and the app checks the signature before it replaces anything. It asks before installing.
4 · Works with your AI
Your AI coding agent drives it. Safely.
Skills, an MCP server and the CLI: the same tools for every agent. The skills are plain Markdown and the CLI is a normal command, so nothing requires a particular tool, or any agent at all.
- Claude Code
- OpenAI Codex
- Cursor
- GitHub Copilot
- Gemini CLI
- Windsurf
- OpenCode
- anything that reads AGENTS.md
Connect your tool
Claude Code
/plugin marketplace add https://git.crt.fyi/CRT/storebound.git
/plugin install storebound@crtkafaSkills, MCP server and storebound on PATH. Or per project: npx storebound install --agent claude
OpenAI Codex
npx storebound install --agent codexSkills in .agents/skills, MCP in .codex/config.toml (Codex reads it for trusted projects). The repo is also a Codex plugin, skills only.
Gemini CLI
gemini extensions install https://git.crt.fyi/CRT/storebound.gitSkills, MCP server and GEMINI.md. Or npx storebound install --agent gemini
Cursor
npx storebound install --agent cursorSkills in .agents/skills and .cursor/mcp.json. The repo's .cursor/rules/storebound.mdc is an agent-requested rule you can copy.
VS Code / GitHub Copilot
npx storebound install --agent copilotSkills in .github/skills and .vscode/mcp.json.
Windsurf (Devin Desktop)
npx storebound install --agent windsurfSkills in .agents/skills, MCP in your global mcp_config.json.
OpenCode
npx storebound install --agent opencodeSkills in .opencode/skills and opencode.json.
Anything that reads AGENTS.md
Copy or link AGENTS.md (rules and skill index) into your project and use the CLI. For an MCP client install does not know: command npx (or bunx) with args ["storebound", "mcp"].
install takes several agents at once (--agent codex,cursor), --dry to preview, and only touches its own storebound entry and skill folders. Re-running it is safe.
Every write is a dry run first
$ storebound play products --dry
[play] 1/2 com.example.app.no_ads: would create · 174 regions · 2 listings (dry)
[play] 2/2 com.example.app.gems_100: would create · 174 regions · 2 listings (dry)
dry run: play products: 2 change(s); nothing written
item action detail
------------------------ ------ ---------------------------------
com.example.app.no_ads create 174 regions, 2 listings, USD 2.99
com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
[play] not on Google Play: com.example.app.no_ads, com.example.app.gems_100. If you created them in the last minutes, the store's list can lag a minute after creating; re-run before acting on this plan
[play] products checked (dry run, nothing written)
Dry run everywhere
Every write command takes
--dry; every MCP write tool hasdry_run, default true.The owner's buttons stay yours
Submitting, releasing, completing a rollout, canceling a submission, deleting and creating offer codes are not MCP tools; the terminal commands ask first.
Credentials stay local
Store accounts once per machine in
~/.storebound/credentials(files only you can read, shared by the CLI and the desktop app), the rest in the project's gitignored.storebound/. Official store APIs only, with keys you create and can revoke, never your password.Idempotent writes
Re-running converges (MD5 checks for screenshots and previews, one Play edit per language), so a failed upload is fixed by running it again.
Personal data stays local
Tester lists, the App Review demo account, reply drafts and reports live in
.storebound/, masked in every log line.Careful with your devices
storebound shuts down only a simulator it booted itself, and never boots, wipes or reboots an Android emulator or device.
What a session with your agent looks like
you: Add a yearly Pro plan with a 1-week free trial and a monthly plan, on both stores.agent: Adding both to subscriptions in storebound.config.ts (USD 29.99 / 3.99, Turkey set by hand). Dry runs first.$ bunx storebound check
09:41:02 [check] config ok: storebound.config.ts
09:41:02 [check] subscriptions: 2 in 1 group(s)
09:41:02 [check] all good
$ bunx storebound apple subscriptions --dry
09:41:05 [apple] reading subscription groups, subscriptions, ...
09:41:07 [apple] 1/9 create subscription group "Tidy Pro"
09:41:07 [apple] 3/9 create pro_yearly (ONE_YEAR, level 1)
09:41:07 [apple] 6/9 pro_yearly: introductory offer FREE_TRIAL P1W
09:41:07 [apple] subscriptions planned (dry run, nothing written; ...) (5s)
$ bunx storebound play subscriptions --dry
09:41:10 [play] 1/2 pro_yearly: create, base plan yearly (P1Y) in 173 regions · intro offer intro (free)
09:41:10 [play] 2/2 pro_monthly: create, base plan monthly (P1M) in 173 regions
09:41:10 [play] subscriptions planned (dry run, nothing written) (3s)
agent: Plan matches the config. Create them on both stores?you: yes$ bunx storebound apple subscriptions && bunx storebound play subscriptions
09:42:31 [apple] group "Tidy Pro" created
09:42:33 [apple] 1/2 pro_yearly: created
09:42:52 [apple] subscriptions done (first ones are submitted with an app version: ...) (21s)
09:43:04 [play] pro_yearly: base plan yearly activated
09:43:05 [play] pro_yearly: offer intro created and activated
09:43:07 [play] subscriptions done (25s)
$ bunx storebound validate
1. BLOCKER [apple] pro_yearly: no review screenshot
fix: subscriptions[].reviewScreenshot, then storebound apple subscriptions
2. warn [apple] description without a Terms of Use link: tr (3.1.2; ...)
09:43:20 [validate] 1 blocker(s)
agent: Left for you: a paywall screenshot for the reviewer (I'll upload it), the Terms link in the Turkish description, and in App Store Connect, adding the first subscriptions to the version's submission (no API; I'll walk you through it).Submit for review · your click
What it covers
Everything an app or game needs, before and after review.
- SubscriptionsApple groups and levels, Play base plans, regional prices, free trials, offers and offer codes.
- One catalog, both storesConsumables, non-consumables, passes and subscriptions from one list; a parity report per region.
- Every questionnaireData safety through the API; IARC, target audience, App Privacy prepared and driven by your agent.
- Review access, account deletionA demo account for the reviewer, kept local; Apple 5.1.1(v) and Play's delete-account page.
- Store artScreenshots in every size and language, fonts for every script, app previews, A/B variants.
- TestFlightGroups, testers from a local CSV, What to Test in every language, build processing.
- After launchCrash and ANR health, review reply drafts, prices from one CSV, analytics, product page tests.
- Many apps, release trainsA workspace for studios, one train per version across both stores, repo-local workflows.
- Growth extrasPPP prices, Apple Ads reports, web presence (app links), ad-hoc builds, RevenueCat sync.
- Every API endpointEvery App Store Connect and Google Play operation; GETs run, writes stay dry.
- Coming from fastlanestorebound import fastlane turns deliver and supply metadata into storebound files.
- Skills and MCPAgent Skills for each store task and an MCP server with read and dry-run tools.
All of it in detail: the docs (opens in a new tab), or storebound help.
5 · Install and start
Five steps, from an empty folder to your Submit click.
storebound lives in your app's repo. Describe the app once, add your keys, then ask your agent or run the commands yourself.
-
Start in your app repo
Pick a profile. Adds config and store files, never overwrites.
$ npx storebound init --profile app $ npx storebound desktop # optional: installs the app once, opens this folderProfilesappsubscription-appgamestorebound.config.tsids, languages, products, Data safetystore/listing text, questionnaire answers, screenshot captions.storebound/this app's upload key and review contact, gitignored
storebound is installed once per machine; each project has its
storebound.config.tsand.storebound/. Needs Node 20+ (or Bun (opens in a new tab) 1.1+ withbunx), plusffmpegfor icons, screenshots and video.Step 1 of 5 -
Describe the app once
One config for both stores, checked offline.
const config: ShipConfig = { app: { name: 'My App', profile: 'app' }, languages: [ { id: 'en', play: 'en-US', apple: 'en-US' }, { id: 'tr', play: 'tr-TR', apple: 'tr' }, ], play: { packageName: 'com.example.app' }, apple: { bundleId: 'com.example.app' }, };$ npx storebound checkStore text lives next to it in
store/listing.mdandstore/appstore.md, one section per language.Step 2 of 5 -
Add your store keys
Official API keys you create and can revoke.
{ "PLAY_SERVICE_ACCOUNT": "/keys/play.json", "ASC_KEY_ID": "KEY_ID", "ASC_ISSUER_ID": "ISSUER_ID", "ASC_P8": "/keys/AuthKey_KEY_ID.p8" }A Play service account and an App Store Connect API key, once for every project on this machine (the desktop app's Accounts screen writes the same file; keys already in a project:
npx storebound accounts import). Env vars work too. Never your password, never committed.Step 3 of 5 -
Connect your agent, ask in plain words
It runs dry runs first and walks you through console-only forms.
$ npx storebound install --agent claudeOr
codex,cursor,copilot,gemini,windsurf,opencode(per tool). No agent? Every step is a CLI command too.- Set up my in-app products on both stores
- Make store screenshots in 14 languages
- What still blocks my submission?
Step 4 of 5 -
Zero blockers, then you submit
A read-only check of both stores, in fix order.
$ npx storebound validate- Blockers, per store, in fix orderbuild, encryption, metadata, screenshots, review details, prices, products
- Fix, run again, until zeroread-only, so it is safe to run as often as you like
- You press Submit for reviewand Send changes for review on Play. Never the agent.
Step 5 of 5Get the desktop app too
Built for
-
Indie developers
One app or a handful: the store chores without a week of console tabs.
-
Studios shipping many titles
One config per title, the same checks and store art pipeline every time.
-
Agencies
Reviewable config in the client's repo. Their keys, their Submit.
FAQ
Questions, answered.
The short version. The docs have the long one, with every command and what each store allows through its API.
Read the docs (opens in a new tab) Ask on the issue tracker (opens in a new tab)
Do I need an AI agent?
No. Every step is a CLI command too (npx storebound --help), and the skills are Markdown checklists you can read yourself for the console-only forms. The agent integrations are optional.
Will it press Submit for me?
No, never. Submitting, releasing, completing a rollout and deleting are not MCP tools, and the terminal commands for them ask first. storebound gets you to zero blockers; you press Submit for review on the App Store and Send changes for review on Play.
Is it only for games?
No. --profile app (the default) and --profile subscription-app bring templates for utility and subscription apps: accounts, account deletion, demo accounts for review, subscriptions on both stores and a calm screenshot style. --profile game is for free-to-play games with ads and in-app purchases.
Where do my keys go? Is my store account safe?
In environment variables or .storebound/credentials.json, which init gitignores. storebound uses the official store APIs with keys you create and can revoke, never your password. Use an App Store Connect key with the App Manager role and a Play service account limited to your app. Every write is a dry run until you say yes.
My app is Unity, Godot, Flutter, React Native or native.
Fine. The store commands work on build numbers and listing files, not engines. Screenshots and clips come from a web build, the iOS Simulator, an Android emulator or device, or a folder of your own frames.
Does it cost anything? Any telemetry?
It is free and open source under the MIT license. No account, no sign-up, no telemetry: it only talks to the Google Play and App Store Connect APIs with your keys. You still need your own Play Console and Apple Developer accounts.
Can I use it for many apps?
Yes. Each app or game gets its own config in its own repo, so the same checks and store art pipeline run for every title. If you ship many similar apps, storebound originality --against <folders> compares one against the others offline (listing text, name, icon and screenshot perceptual hashes, project structure) for Apple's spam guideline (4.3) and Play's repetitive content policy, and exits with 1 on a near-duplicate. storebound scan --originality runs the same check as part of the scan, and the portfolio-originality skill walks your agent through the fixes.
Does it run on Windows or Linux?
It runs on Node 20+ (npx storebound) and on Bun 1.1+ (bunx storebound). The store commands are API calls. Capturing from the iOS Simulator needs a Mac with Xcode; a web build, an Android emulator or a folder of frames works anywhere. Icons, screenshots and video also need ffmpeg.

1024 iOS
512 Play