- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and "Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot, config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it - tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded (replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci - package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20 - bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help, init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/ - install writes npx MCP commands when run with Node; bin/storebound falls back to Node - docs: npx storebound init (Node 20+) or bunx storebound init
117 lines
7.6 KiB
Markdown
117 lines
7.6 KiB
Markdown
# Getting started
|
|
|
|
## 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/<date>.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 <name>.imported.<ext> 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/<locale>/*.txt` (+ `default/`) | `store/appstore.md` per App Store locale; URLs, copyright, categories and review notes in the config |
|
|
| supply `metadata/android/<lang>/*.txt`, newest `changelogs/<versionCode>.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/<locale>/`, `images/phoneScreenshots/`, `tenInchScreenshots/` | `store/shots/frames/<lang>/<phone\|tablet>/NN.png` with a `folder` capture source |
|
|
| supply `icon`, `featureGraphic` | `play.icon`, `store/renders/<lang>/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)
|
|
|
|
Read from environment variables, or from `.storebound/credentials.json` in your project (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_<id>.p8` (default `~/.appstoreconnect/private_keys/AuthKey_<id>.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: credential profiles (`~/.storebound/credentials/<profile>.json`, the same names
|
|
except the per-app upload keystore)
|
|
picked with `--account <profile>` 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 "<cmd>"` 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)
|