# Getting started **The model.** storebound is installed once per machine (`npx storebound` / the desktop app, one version number). Each project has its `storebound.config.ts` and a gitignored `.storebound/` folder (upload keystore, review contact and demo account). Store accounts live once per machine in `~/.storebound/credentials` (shared by CLI and app: `storebound accounts`), and so does the list of app folders (`~/.storebound/projects.json`: `storebound apps folders`, the desktop's App folders). `npx storebound desktop` installs the app (asks once) and opens it on the current folder. ## 5-minute quick start You need [Node](https://nodejs.org) 20+ or [Bun](https://bun.sh) 1.1+ (and `ffmpeg` for icons, screenshots and video). With Node, run the commands as `npx storebound ...`; with Bun, as `bunx storebound ...` (used below). Both run the same CLI. ```sh cd my-app npx storebound init # Node 20+ (npm i -D storebound playwright to pin it in the project) bunx storebound init # or Bun (bun add -d storebound playwright, or bun add -d git+https://git.crt.fyi/CRT/storebound.git playwright) # --profile app (default) | subscription-app | game: config, store/*.md, declarations, privacy policy, .storebound/ (gitignored) # fill in storebound.config.ts and the store/ files bunx storebound check # offline: config, copy limits, Data safety answers, products, files ``` Add credentials (below), then walk the journey with dry runs first: ```sh bunx storebound apple bundle --dry bunx storebound play listing --dry bunx storebound play products --dry && bunx storebound apple iap --dry bunx storebound apple subscriptions --dry && bunx storebound play subscriptions --dry bunx storebound apple review-details --dry # contact + demo account from .storebound/ (masked) + notes bunx storebound play data-safety --dry --csv store/data-safety.csv bunx storebound apple appinfo --dry bunx storebound icons --dry bunx storebound shots capture && bunx storebound shots render && bunx storebound shots gallery bunx storebound validate # read-only: what still blocks a submission, per store, in fix order bunx storebound catalog diff # read-only: products + subscriptions on both stores vs the config, prices per region ``` After launch: ```sh bunx storebound apple testflight what-to-test --build 42 --dry # then distribute --build 42 --group Team bunx storebound health --weekly # vitals + diagnostics, .storebound/health/.md bunx storebound reviews draft # reply drafts in .storebound/replies/, then reviews send bunx storebound prices export && bunx storebound prices import --dry bunx storebound analytics snapshot && bunx storebound analytics compare ``` Or ask your agent: "take my app to Google Play and the App Store", "fill in the store questionnaires", "set up the in-app purchases and a yearly subscription with a free trial on both stores", "do both stores sell the same catalog", "the reviewer could not sign in", "make store screenshots in 5 languages", "is my app ready to submit", "why was my update rejected", "put build 42 on TestFlight", "how are our crash rates", "answer the new reviews", "did the new screenshots help". The matching skill takes over. ## Coming from fastlane `storebound import fastlane` turns an existing fastlane setup into storebound files. It only reads (no Ruby is run), never overwrites anything and prints what it could not map: ```sh bunx storebound import fastlane --dry # the plan + report; default --dir: fastlane/, ios/fastlane/, android/fastlane/ bunx storebound import fastlane # writes the files below; an existing file gets a .imported. copy bunx storebound init # adds the remaining templates, keeps the imported files bunx storebound check ``` | fastlane | storebound | |---|---| | Appfile `app_identifier`, `package_name` | `apple.bundleId`, `play.packageName` | | deliver `metadata//*.txt` (+ `default/`) | `store/appstore.md` per App Store locale; URLs, copyright, categories and review notes in the config | | supply `metadata/android//*.txt`, newest `changelogs/.txt` | `store/listing.md` per Play language | | deliver and supply language folders | `languages[]` with both store codes (`tr` + `tr-TR`, `zh-Hans` + `zh-CN`, `he` + `iw-IL`) | | `screenshots//`, `images/phoneScreenshots/`, `tenInchScreenshots/` | `store/shots/frames///NN.png` with a `folder` capture source | | supply `icon`, `featureGraphic` | `play.icon`, `store/renders//feature/1024x500.*` | Keys and accounts are never copied: `json_key_file`, the API key, team ids, the App Review contact and demo account are named in the report with where they go (`.storebound/credentials.json`). Submission and release flags, `price_tier`, the age rating config, lanes and signing (`match`) are listed with their storebound counterpart. The `migrate-from-fastlane` skill walks an agent through it. ## Credentials (never in the repo) Store accounts belong to the machine, everything else to the project: - **Store accounts** (App Store Connect team key, Play service account, vendor number): a credential profile in `~/.storebound/credentials/.json`, its key files next to it in `/` (mode 0600). The desktop app adds and reads the same profiles. Already have the keys in a project's `.storebound/credentials.json`? Move them once: `npx storebound accounts import --dry`, then `npx storebound accounts import --yes` in every project: the same key id or service account is one profile (`default` for the first one), and the project file keeps the rest and gets `"account": ""`. `npx storebound accounts` lists the profiles and which one this folder uses. - **Which profile:** `--account ` for one run, `account: ''` in the config, `"account"` in the project's `.storebound/credentials.json`, else the only profile on the machine (or the one named `default`). - **Per project:** the Android upload keystore, the App Review contact and demo account stay in the project's `.storebound/credentials.json`. - **Order:** environment variables win over everything, then a profile the project names, then the project file, then the default profile. The names (env, profile and project file alike; the project file is gitignored by `init`): | name | what | |---|---| | `PLAY_SERVICE_ACCOUNT` | path to the Google Cloud service account JSON key (or the JSON itself) with access to your app in Play Console | | `ASC_KEY_ID`, `ASC_ISSUER_ID` | App Store Connect API team key (Users and Access > Integrations) | | `ASC_P8` | path to `AuthKey_.p8` (default `~/.appstoreconnect/private_keys/AuthKey_.p8`) | | `ASC_VENDOR_NUMBER` | vendor number for `reports apple-sales` / `apple-finance` (Payments and Financial Reports) | | `ANDROID_KEYSTORE`, `ANDROID_KEYSTORE_PASSWORD`, `ANDROID_KEY_ALIAS`, `ANDROID_KEY_PASSWORD` | upload key for `play build` (path to the .jks / .p12 and its passwords; handed to Gradle through the environment) | | `reviewContact` | (file only) App Review contact name / phone / email | | `reviewDemoAccount` / `REVIEW_DEMO_USER`, `REVIEW_DEMO_PASSWORD` | demo account for App Review (`reviewAccess.signInRequired`); never in the config or the repo, masked in logs | Several store accounts on one machine: one profile each, picked as above or by a workspace ([Many apps and studios](studios.md#many-apps-and-studios)). ## Install for your AI tool Every route gives the agent the same skills and the same MCP tools. Nothing here requires Claude: the skills are plain Markdown and the CLI is a normal command. | tool | install | |---|---| | Claude Code | `/plugin marketplace add https://git.crt.fyi/CRT/storebound.git` then `/plugin install storebound@crtkafa` (skills, MCP server, `storebound` on PATH). Or per project: `bunx storebound install --agent claude` | | OpenAI Codex | `bunx storebound install --agent codex` (skills in `.agents/skills`, MCP in `.codex/config.toml`; Codex reads that file for trusted projects). The repo is also a Codex plugin (`.codex-plugin/plugin.json`, skills only) | | Gemini CLI | `gemini extensions install https://git.crt.fyi/CRT/storebound.git` (skills, MCP server, `GEMINI.md`). Or `bunx storebound install --agent gemini` | | Cursor | `bunx storebound install --agent cursor` (skills in `.agents/skills`, `.cursor/mcp.json`); the repo's `.cursor/rules/storebound.mdc` is an agent-requested rule you can copy | | VS Code / GitHub Copilot | `bunx storebound install --agent copilot` (skills in `.github/skills`, `.vscode/mcp.json`) | | Windsurf (Devin Desktop) | `bunx storebound install --agent windsurf` (skills in `.agents/skills`, MCP in your global `mcp_config.json`) | | OpenCode | `bunx storebound install --agent opencode` (skills in `.opencode/skills`, `opencode.json`) | | anything that reads `AGENTS.md` | copy or link `AGENTS.md` (rules + skill index) and use the CLI | `install` takes several agents at once (`--agent codex,cursor`), `--dry` to preview, `--no-skills` / `--no-mcp`, and `--command ""` to choose how the MCP server starts. It only adds or updates the `storebound` entry and its own skill folders; everything else in those files stays as it is, and re-running it is safe. --- [All docs](README.md) ยท [README](../README.md)