0.3.1: README around the zero-to-Submit journey, journey diagram, new positioning in package and plugin descriptions

This commit is contained in:
CRTkafa 2026-10-10 22:49:27 +08:00
parent c43c20f370
commit 74dbf8f5a6
9 changed files with 289 additions and 82 deletions

View file

@ -8,8 +8,8 @@
{ {
"name": "storebound", "name": "storebound",
"source": ".", "source": ".",
"description": "Ship mobile games to Google Play and the App Store: skills for every store step plus the storebound CLI and MCP server.", "description": "Take a mobile game from nothing to Submit for review on both stores: skills for every store step and questionnaire plus the storebound CLI and MCP server.",
"version": "0.3.0", "version": "0.3.1",
"category": "development", "category": "development",
"tags": [ "tags": [
"mobile", "mobile",

View file

@ -1,7 +1,7 @@
{ {
"name": "storebound", "name": "storebound",
"version": "0.3.0", "version": "0.3.1",
"description": "Ship mobile games to Google Play and the App Store: store listings, in-app products, data safety, screenshots, icons, release management and review checklists, as Agent Skills plus a Bun CLI and MCP server (storebound). CRTkafa's own toolchain, open-sourced.", "description": "From nothing to Submit for review on Google Play and the App Store: app records, listings in every language, in-app products with regional prices, every questionnaire (Data safety, IARC, target audience, ads, App Privacy, age rating, export compliance), privacy, icons, screenshots and previews, validate, release management. Agent Skills plus a Bun CLI and MCP server (storebound); you press Submit. CRTkafa's own toolchain, open-sourced.",
"author": { "author": {
"name": "CRTkafa" "name": "CRTkafa"
}, },

View file

@ -1,7 +1,7 @@
{ {
"name": "storebound", "name": "storebound",
"version": "0.3.0", "version": "0.3.1",
"description": "Ship mobile games to Google Play and the App Store: store listings, in-app products, data safety, screenshots, icons, release management and review checklists, as Agent Skills plus a Bun CLI and MCP server (storebound). CRTkafa's own toolchain, open-sourced.", "description": "From nothing to Submit for review on Google Play and the App Store: app records, listings in every language, in-app products with regional prices, every questionnaire (Data safety, IARC, target audience, ads, App Privacy, age rating, export compliance), privacy, icons, screenshots and previews, validate, release management. Agent Skills plus a Bun CLI and MCP server (storebound); you press Submit. CRTkafa's own toolchain, open-sourced.",
"author": { "author": {
"name": "CRTkafa" "name": "CRTkafa"
}, },

View file

@ -1,5 +1,18 @@
# Changelog # Changelog
## 0.3.1 · 2026-10-10
Positioning: storebound is the whole road from zero to "Submit for review", screenshots are one step of it.
- **README** rebuilt around the end-to-end journey: a new diagram (`docs/img/journey.svg`) and a step table for both
stores showing what storebound does through the APIs, what the skills walk your agent through in the consoles
(IARC, target audience, ads, advertising ID, App Privacy, app records, the first Play production send) and what
stays your own click (Send for review / Submit for Review, releases). "API or console, honestly" summary, a new FAQ
("Does it fill the questionnaires?"), quick start along the journey with the npm package, skills in journey order;
the screenshot and video showcase moved to a "Store art" section.
- Package, plugin, Codex, Gemini and marketplace descriptions follow the new positioning.
- `package.json` `bin` path normalised (`cli/index.ts`), so npm keeps the `storebound` command.
## 0.3.0 · 2026-10-10 ## 0.3.0 · 2026-10-10
Screenshots and videos from any engine, reviewed before they leave your machine. Screenshots and videos from any engine, reviewed before they leave your machine.

181
README.md
View file

@ -1,59 +1,71 @@
# storebound # storebound
[![license: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
[![version 0.3.0](https://img.shields.io/badge/version-0.3.0-informational)](CHANGELOG.md) [![version 0.3.1](https://img.shields.io/badge/version-0.3.1-informational)](CHANGELOG.md)
[![runtime: Bun](https://img.shields.io/badge/runtime-Bun%201.1%2B-f9f1e1)](https://bun.sh) [![runtime: Bun](https://img.shields.io/badge/runtime-Bun%201.1%2B-f9f1e1)](https://bun.sh)
[![runtime dependencies: 0](https://img.shields.io/badge/runtime%20dependencies-0-brightgreen)](package.json) [![runtime dependencies: 0](https://img.shields.io/badge/runtime%20dependencies-0-brightgreen)](package.json)
[![Agent Skills: 17](https://img.shields.io/badge/Agent%20Skills-17-8a63d2)](skills) [![Agent Skills: 17](https://img.shields.io/badge/Agent%20Skills-17-8a63d2)](skills)
[![MCP: stdio](https://img.shields.io/badge/MCP-stdio-black)](#mcp-server) [![MCP: stdio](https://img.shields.io/badge/MCP-stdio-black)](#mcp-server)
Hey, I'm CRTkafa. This is my toolchain for shipping mobile games to Google Play and the App Store. I built it while **Take a mobile game from nothing to "Submit for review" on Google Play and the App Store: app records, listings in
getting my own game through both stores, hit every wall on the way (draft apps, edits that die when you touch the every language, in-app products with regional prices, every questionnaire, privacy, icons, screenshots and previews,
Console, the "first IAP must ship with a version" dance, data safety CSVs that silently need one more answer, with one config and your AI coding agent.**
screenshots in 7 sizes x 14 languages...) and wrote each fix down as code or as a checklist. It works for me, so I
open-sourced it. Use it too. Hey, I'm CRTkafa. I built this while getting my own game through both stores and hit every wall on the way: draft
apps, edits that die when you touch the Console, the "first IAP must ship with a version" dance, Data safety CSVs that
silently need one more answer, an IARC questionnaire, target audience, App Privacy labels that are saved but not
published, screenshots in 7 sizes x 14 languages... I wrote each fix down as code or as a checklist. It works for me,
so I open-sourced it. Use it too.
It is not a product: no dashboard, no account, no telemetry. A small Bun CLI that talks to the official store APIs, It is not a product: no dashboard, no account, no telemetry. A small Bun CLI that talks to the official store APIs,
Agent Skills that walk you (or your AI coding tool, whichever it is) through the parts that are still clicks, and an Agent Skills that walk your AI coding tool (or you) through the parts that are still console clicks, and an MCP server
MCP server so agents can call the CLI safely. so agents can call the CLI safely. **storebound never presses Submit, Release or Publish for you.**
## Showcase ![The journey: config, app records, products, listings, questionnaires, privacy and icons, store art, validate, then you press Submit](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/journey.svg)
Everything below was made by storebound itself from [a tiny demo game](examples/demo-game) ("Prism Puddle", ## The journey
fictional, procedural art): raw frames captured from the web build, captions in 4 languages, every store size,
a review gallery and an app preview video. No store account needed to try it.
![Store screenshots rendered by storebound: four scenes in English plus the hero scene in Turkish, Japanese and Arabic](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/showcase.jpg) Everything a game needs before review, in the order I do it. For each step: what storebound does through the store
APIs (or on your machine), what the skill walks your agent through where the stores have no public API, and what stays
your own click.
| Play feature graphic | App preview (App Store, 886 x 1920) | - **storebound**: a CLI command (also an MCP tool). Every write has `--dry`; MCP write tools default to a dry run.
|---|---| - **skill + agent (UI)**: no public API exists for it. The named skill has the exact navigation and the prepared
| ![Play feature graphic, 1024 x 500](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/feature.jpg) | ![A few seconds of the app preview video](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/preview.gif) | answers. An agent with browser tools (a Chrome extension, computer use, a Playwright MCP ...) can click through it
while you watch; without one, you click with the skill as your checklist.
- **you**: public, legal or money steps. The skills tell every agent to stop and hand these to you.
![The review gallery: every language, size, scene and variant on one local page, store check issues highlighted](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/gallery.jpg) | # | step | storebound (API / local) | skill + agent (UI) | you |
|---|---|---|---|---|
| 1 | **Set up** | `init` (config, `store/*.md`, declarations and privacy templates), `install --agent <tool>`, `check` | Play: service account + API access invite; App Store: API team key (`play-first-release`, `appstore-first-release`) | developer accounts; Paid Applications agreement, banking and tax; Play payments profile |
| 2 | **App records and bundle id** | `apple bundle` registers the bundle id, `apple status` finds the app record | App Store Connect > New App (no API); Play Console > Create app; the very first AAB upload when Play needs it from the Console | the declarations you accept when creating the Play app |
| 3 | **Builds** | `play next-version-code`, `play release app.aab` (internal track), `apple next-build`, `xcodebuild` archive + upload with the API key (the skill has the commands), `apple encryption` | TestFlight internal group, internal testers (`appstore-first-release`, `play-first-release`) | |
| 4 | **In-app products** | `play products` (regional prices from USD + your overrides, activated), `apple iap` (localizations, price schedule, availability), `apple iap-review` (review screenshots) | Play license testers, Apple sandbox testers, "Add for Review" of the first IAPs into the version's submission (`store-iap-setup`) | |
| 5 | **Store listings, every language** | `play listing` (title, short / full description, contact email + website, promo video URL), `apple listing --version x --build N` (name, subtitle, description, keywords, promo text, URLs, privacy URL, manual release), `whats-new`, `check` (limits), `check --aso` | Play store settings: category and tags (`play-first-release`) | |
| 6 | **Play questionnaires** | `play data-safety`: the whole Data safety form from `dataSafety` in the config (CSV import through the API) | Policy and programs > App content, answers prepared in `store/declarations.md` (`store-declarations`): privacy policy, app access / sign-in details, ads, content rating (IARC), target audience and content, advertising ID, news, government, financial and health features; Data safety summary check | the answers themselves are your statements: the agent asks when the code does not prove them |
| 7 | **App Store questionnaires** | `apple appinfo` (categories, age rating declaration, content rights, Free price, availability), `apple encryption` (export compliance from `apple.usesNonExemptEncryption`, never guessed), `apple review-details` (contact + notes) | App Privacy nutrition labels from `store/app-privacy.md`, then **Publish** (`store-declarations`); encryption documentation when the answer is yes (`export-compliance`); the first availability record if the API refuses it | the export compliance answer (a legal statement, set once in the config) |
| 8 | **Privacy** | privacy policy page template (`init`), `privacy-manifest --ios <path>` (PrivacyInfo.xcprivacy, required-reason APIs, SDK manifests), `validate` checks the policy URL answers | host the page, link it in both consoles and inside the game (`privacy-policy`, `privacy-manifest`) | |
| 9 | **Icons** | `icons`: App Store 1024 without alpha, Play 512, adaptive + legacy Android launcher icons, web icons, Capacitor sources | | |
| 10 | **Screenshots and previews** | `shots capture / render / check / gallery`, `play images`, `apple screenshots`, `shots record / video`, `apple previews` (see [Store art](#store-art)) | Play store listing experiments, App Store Product Page Optimization (optional, `store-screenshots`) | uploading the promo video to YouTube |
| 11 | **Validate** | `check` (offline) and `validate` (read-only on both stores: every blocker in fix order, plus the local renders) | the UI-only items `validate` cannot see (`store-preflight` lists them) | |
| 12 | **Submit** | `play release --version-code N --production draft`, `apple status` | Play: countries / regions, open the production draft and save it (`play-first-release`) | **Play: Send changes for review. App Store: Submit for Review.** |
| 13 | **After review** | `apple status --wait-review`, `apple release --phased on / pause`, `play rollout --halt`, reply drafts (`review-rejections`) | | releasing the approved version, resuming or completing a phased release or rollout (terminal commands that ask first, `release-management`) |
<details> New personal Play developer accounts also need a closed test with 12+ testers for 14 days before production; the
<summary>Contact sheet of one language (every size, packed into a grid)</summary> `play-first-release` skill covers it.
![Contact sheet: iPhone 6.9" and 6.5", 13" iPad, Play phone, 7" and 10" tablets, feature graphic](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/sheet.jpg) ### API or console, honestly
</details> - **Through the API** (storebound does it): bundle id, builds on tracks, versions and build selection, listings in
every language, graphics, screenshots, app previews, in-app products and prices, Play Data safety, Apple age rating,
## What it does categories, content rights, price and availability, export compliance answer, App Review details, phased release
and staged rollout.
- **Store listings and products**: Play listings and one-time products with regional prices, App Store versions, - **Console only** (no public API; the skill + your agent's browser, or you): creating the App Store Connect app record
localizations, in-app purchases, price schedules, age rating, review details, export compliance. and the Play app, Play App content (IARC content rating, target audience, ads, advertising ID, app access,
- **Releases**: AAB uploads to tracks, staged rollouts (halt / resume / complete), phased release on the App Store, government / financial / health / news), Play category and tags, Play countries, App Privacy labels and their
next build numbers, waiting for review, release notes drafted from git. Publish, TestFlight groups, adding first IAPs to the submission, store experiments.
- **Readiness**: `check` (offline: config, copy limits, Data safety, ASO) and `validate` (read-only against both - **Only you**: agreements, banking and tax, and the final Send for review / Submit for Review. Releases and
stores: what still blocks a submission, in fix order), privacy manifest scan. rollouts after approval too. None of these is an MCP tool.
- **Screenshots from any engine**: capture raw frames from a web build, the iOS Simulator, an Android emulator or a
folder; render captioned scenes with device frames in every store size and language (RTL and CJK included), A/B
variants, local store checks, a review gallery, uploads to both stores.
- **App previews and promo video**: record gameplay clips, cut App Store previews and a YouTube promo with captions,
check them against Apple's rules, upload previews per locale.
- **Icons** for both stores and Android launchers from one artwork.
- **Agent Skills** for every step, including the ones that are still console clicks (with the exact navigation).
- **MCP server** with one tool per command, dry run by default, nothing irreversible exposed.
## 5-minute quick start ## 5-minute quick start
@ -61,25 +73,28 @@ You need [Bun](https://bun.sh) 1.1+ (and `ffmpeg` for icons, screenshots and vid
```sh ```sh
cd my-game cd my-game
bun add -d git+https://git.crt.fyi/CRT/storebound.git playwright bun add -d storebound playwright # or: bun add -d git+https://git.crt.fyi/CRT/storebound.git playwright
bunx storebound init # storebound.config.ts, store/*.md, store/shots/copy.json, privacy policy, .storebound/ (gitignored) bunx storebound init # storebound.config.ts, store/*.md, declarations, privacy policy, .storebound/ (gitignored)
# fill in storebound.config.ts and the store/ files # fill in storebound.config.ts and the store/ files
bunx storebound check # offline: config, copy limits, data safety, files bunx storebound check # offline: config, copy limits, Data safety answers, products, files
bunx storebound shots capture --dry && bunx storebound shots capture
bunx storebound shots fonts && bunx storebound shots render --lang en
bunx storebound shots gallery # open store/renders/index.html
``` ```
When the store side is ready, add credentials (below) and: Add credentials (below), then walk the journey with dry runs first:
```sh ```sh
bunx storebound validate # read-only: what still blocks a submission, per store, in fix order bunx storebound apple bundle --dry
bunx storebound play listing --dry bunx storebound play listing --dry
bunx storebound apple iap --dry bunx storebound play products --dry && bunx storebound apple iap --dry
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
``` ```
Or ask your agent: "ship my game to Google Play", "set up the in-app purchases on both stores", "make store Or ask your agent: "take my game to Google Play and the App Store", "fill in the store questionnaires", "set up the
screenshots in 5 languages", "make an app preview", "why was my update rejected". The matching skill takes over. in-app purchases on both stores", "make store screenshots in 5 languages", "is my app ready to submit", "why was my
update rejected". The matching skill takes over.
### Credentials (never in the repo) ### Credentials (never in the repo)
@ -112,16 +127,6 @@ plain Markdown and the CLI is a normal command.
and `--command "<cmd>"` to choose how the MCP server starts. It only adds or updates the `storebound` entry and its 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. own skill folders; everything else in those files stays as it is, and re-running it is safe.
## Automatic vs manual
| | automatic (CLI / API) | still manual (the skills give the exact clicks) |
|---|---|---|
| **Google Play** | listing text + promo video URL, graphics and screenshots, one-time products with regional prices, Data safety, AAB upload to tracks, staged rollout, release notes, status, next versionCode, readiness report | creating the app, API access + service account invite, App content declarations (privacy policy, ads, IARC rating, target audience, advertising ID, sign-in details), countries, store listing experiments, **Send for review** on a draft app's first release |
| **App Store** | bundle id, version + build, localizations, screenshots (iPhone + iPad), app previews, in-app purchases with prices and review screenshots, categories, age rating, review details, export compliance answer, phased / manual release, status and review wait, readiness report | creating the app record, App Privacy labels (+ Publish), TestFlight groups, adding first IAPs to the submission, Product Page Optimization tests, encryption documents when the answer is "yes", **Submit for Review** |
| **Local** | config and copy checks, ASO audit, privacy manifest scan, icons, screenshot capture / render / checks / gallery, clip recording, preview and promo video cutting | uploading the promo video to YouTube, deciding what your screenshots promise |
Public or irreversible steps are left to you on purpose (see [Safety model](#safety-model)).
## Commands ## Commands
Every write command takes `--dry`; re-runs are idempotent; output is one timestamped line per step, so long jobs can Every write command takes `--dry`; re-runs are idempotent; output is one timestamped line per step, so long jobs can
@ -195,7 +200,29 @@ run in the background with a log (`storebound shots render > .storebound/render.
</details> </details>
## Screenshots and video ## Store art
Screenshots and previews are one step of the journey, but the one that takes the longest by hand, so storebound
does a lot here. Everything below was made by storebound itself from [a tiny demo game](examples/demo-game) ("Prism
Puddle", fictional, procedural art): raw frames captured from the web build, captions in 4 languages, every store
size, a review gallery and an app preview video. No store account needed to try it.
![Store screenshots rendered by storebound: four scenes in English plus the hero scene in Turkish, Japanese and Arabic](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/showcase.jpg)
| Play feature graphic | App preview (App Store, 886 x 1920) |
|---|---|
| ![Play feature graphic, 1024 x 500](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/feature.jpg) | ![A few seconds of the app preview video](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/preview.gif) |
![The review gallery: every language, size, scene and variant on one local page, store check issues highlighted](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/gallery.jpg)
<details>
<summary>Contact sheet of one language (every size, packed into a grid)</summary>
![Contact sheet: iPhone 6.9" and 6.5", 13" iPad, Play phone, 7" and 10" tablets, feature graphic](https://git.crt.fyi/CRT/storebound/raw/branch/main/docs/img/sheet.jpg)
</details>
### How it works
1. **Frames.** Give your game a few switches (language, fixed seed, no ads, jump to a scene, freeze, autoplay) and 1. **Frames.** Give your game a few switches (language, fixed seed, no ads, jump to a scene, freeze, autoplay) and
let `shots capture` take the frames: Playwright for a web build, `simctl` for anything that runs in the iOS let `shots capture` take the frames: Playwright for a web build, `simctl` for anything that runs in the iOS
@ -220,25 +247,28 @@ skills.
## Skills ## Skills
In journey order. Each one says which steps are API (storebound) and which are console clicks, with the exact
navigation.
| skill | for | | skill | for |
|---|---| |---|---|
| `play-first-release` | Google Play from zero to "In review" | | `play-first-release` | Google Play from zero to "In review" |
| `appstore-first-release` | App Store from API key to "Waiting for review", incl. xcodebuild with the API key | | `appstore-first-release` | App Store from API key to "Waiting for review", incl. xcodebuild with the API key |
| `release-management` | updates: Apple phased + manual release, Play staged rollout, halt / pause (not a rollback), review wait |
| `store-preflight` | run and read `check`, `check --aso`, `validate`, `privacy-manifest` before submitting |
| `review-rejections` | triage a rejection (fix / clarify / push back / appeal), reply template, the guidelines games hit |
| `portfolio-originality` | Guideline 4.3 gate for studios shipping many similar games |
| `store-iap-setup` | in-app products on both stores, prices, testers, the first-IAP-with-version rule | | `store-iap-setup` | in-app products on both stores, prices, testers, the first-IAP-with-version rule |
| `aso-basics` | keyword field, subtitle, cross-localization, Play placement without stuffing |
| `store-declarations` | every questionnaire: Play Data safety (API) and App content (IARC, target audience, ads, advertising ID, app access, government / financial / health), Apple App Privacy labels and age rating |
| `export-compliance` | encryption answer, Info.plist key, declarations; never exempt by default |
| `privacy-policy` | one studio-wide policy page with a per-game services table |
| `privacy-manifest` | PrivacyInfo.xcprivacy, required-reason APIs, SDK manifests (ITMS-91053 / 91061) |
| `app-icons` | one artwork to every icon, adaptive / legacy launcher pitfalls |
| `store-screenshots` | capture from any engine, copy, fonts, render, checks, gallery, variants and store experiments, upload | | `store-screenshots` | capture from any engine, copy, fonts, render, checks, gallery, variants and store experiments, upload |
| `app-previews` | gameplay clips, App Store previews, Play promo video, checks, upload | | `app-previews` | gameplay clips, App Store previews, Play promo video, checks, upload |
| `app-icons` | one artwork to every icon, adaptive / legacy launcher pitfalls | | `store-preflight` | run and read `check`, `check --aso`, `validate`, `privacy-manifest` before submitting |
| `store-declarations` | Data safety, App Privacy, IARC, target audience, ads / advertising ID | | `release-management` | updates: Apple phased + manual release, Play staged rollout, halt / pause (not a rollback), review wait |
| `export-compliance` | encryption answer, Info.plist key, declarations; never exempt by default |
| `privacy-manifest` | PrivacyInfo.xcprivacy, required-reason APIs, SDK manifests (ITMS-91053 / 91061) |
| `privacy-policy` | one studio-wide policy page with a per-game services table |
| `aso-basics` | keyword field, subtitle, cross-localization, Play placement without stuffing |
| `whats-new` | player-facing release notes from git, localized, within store limits | | `whats-new` | player-facing release notes from git, localized, within store limits |
| `review-rejections` | triage a rejection (fix / clarify / push back / appeal), reply template, the guidelines games hit |
| `ads-levelplay-checks` | LevelPlay / Unity Ads ids, adapters, app-ads.txt, SKAdNetwork, no-fill | | `ads-levelplay-checks` | LevelPlay / Unity Ads ids, adapters, app-ads.txt, SKAdNetwork, no-fill |
| `portfolio-originality` | Guideline 4.3 gate for studios shipping many similar games |
## MCP server ## MCP server
@ -277,6 +307,17 @@ absolute path of `bin/storebound` plus `mcp`).
**Do I need Claude (or any AI tool)?** No. The CLI is a normal command and the skills are Markdown checklists you can **Do I need Claude (or any AI tool)?** No. The CLI is a normal command and the skills are Markdown checklists you can
read yourself. The AI integrations are optional adapters generated from the same files. read yourself. The AI integrations are optional adapters generated from the same files.
**Does it fill the questionnaires?** The ones with an API, yes: Play Data safety (the whole form from `dataSafety` in
the config; the import replaces the form, so the config is the single truth), Apple age rating, content rights,
categories, price and availability, the export compliance answer and the App Review details. The stores have no
public API for Play's App content cards (IARC content rating, target audience, ads, advertising ID, app access,
government / financial / health / news) or for Apple's App Privacy labels. For those, `init` gives you prepared
answers (`store/declarations.md`, `store/app-privacy.md`, written for a typical free-to-play game with ads and IAP),
and the `store-declarations` skill has the exact clicks: an agent with browser tools can fill them in while you
watch, or you copy them in yourself. Either way the answers are your statements to the stores: change what does not
match your game, and the agent asks you whenever the code does not prove an answer. `validate` cannot see these
forms, so `store-preflight` lists them as a manual check.
**My game is Unity / Godot / Flutter / native, not web.** Screenshots and clips come from the iOS Simulator **My game is Unity / Godot / Flutter / native, not web.** Screenshots and clips come from the iOS Simulator
(`ios-sim`), an Android emulator or device (`android-emu`) or a folder you fill with any tool; only the rendering of (`ios-sim`), an Android emulator or device (`android-emu`) or a folder you fill with any tool; only the rendering of
the store images uses a headless browser. The store commands do not care about the engine at all: they work on the store images uses a headless browser. The store commands do not care about the engine at all: they work on

153
docs/img/journey.svg Normal file
View file

@ -0,0 +1,153 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 560" width="960" height="560" role="img" aria-labelledby="t d">
<title id="t">storebound · the journey from zero to Submit for review</title>
<desc id="d">Nine steps: config, app records, products, listings, questionnaires, privacy and icons, store art, validate, and finally you press Submit. Each step is tagged API (storebound command), UI (a skill guides your agent or you through the console), local, or you (your own click).</desc>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#64748b"/>
</marker>
<style>
text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }
.h { font-size: 22px; font-weight: 700; fill: #f8fafc; }
.s { font-size: 13px; fill: #94a3b8; }
.n { font-size: 13px; font-weight: 700; fill: #0f172a; }
.tt { font-size: 14.5px; font-weight: 700; fill: #f1f5f9; }
.l { font-size: 11px; fill: #cbd5e1; }
.tg { font-size: 10.5px; font-weight: 700; letter-spacing: .4px; }
.lg { font-size: 12px; fill: #94a3b8; }
.box { fill: #1e293b; stroke: #334155; stroke-width: 1.2; }
.wire { stroke: #64748b; stroke-width: 2; fill: none; }
</style>
</defs>
<rect x="0" y="0" width="960" height="560" rx="20" fill="#0f172a"/>
<rect x="0.5" y="0.5" width="959" height="559" rx="20" fill="none" stroke="#334155"/>
<text x="28" y="46" class="h">From zero to “Submit for review”</text>
<text x="28" y="70" class="s">Google Play + App Store · one config · your AI coding agent · storebound never presses Submit</text>
<!-- wires -->
<path class="wire" d="M188 179 H212" marker-end="url(#arrow)"/>
<path class="wire" d="M374 179 H398" marker-end="url(#arrow)"/>
<path class="wire" d="M560 179 H584" marker-end="url(#arrow)"/>
<path class="wire" d="M746 179 H770" marker-end="url(#arrow)"/>
<path class="wire" d="M852 254 V284 H108 V312" marker-end="url(#arrow)"/>
<path class="wire" d="M188 389 H212" marker-end="url(#arrow)"/>
<path class="wire" d="M374 389 H398" marker-end="url(#arrow)"/>
<path class="wire" d="M560 389 H584" marker-end="url(#arrow)"/>
<!-- 1 config -->
<g transform="translate(28 104)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">1</text>
<text x="42" y="29" class="tt">Config</text>
<text x="14" y="62" class="l">storebound.config.ts</text>
<text x="14" y="80" class="l">+ store/*.md texts,</text>
<text x="14" y="98" class="l">one section per language</text>
<rect x="14" y="116" width="46" height="20" rx="10" fill="#0c4a6e"/><text x="37" y="130" class="tg" fill="#7dd3fc" text-anchor="middle">LOCAL</text>
</g>
<!-- 2 app records -->
<g transform="translate(214 104)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">2</text>
<text x="42" y="29" class="tt">App records</text>
<text x="14" y="62" class="l">bundle id registered;</text>
<text x="14" y="80" class="l">Play app + App Store</text>
<text x="14" y="98" class="l">Connect record created</text>
<rect x="14" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="31" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
<rect x="54" y="116" width="30" height="20" rx="10" fill="#451a03"/><text x="69" y="130" class="tg" fill="#fcd34d" text-anchor="middle">UI</text>
</g>
<!-- 3 products -->
<g transform="translate(400 104)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">3</text>
<text x="42" y="29" class="tt">Products</text>
<text x="14" y="62" class="l">in-app purchases with</text>
<text x="14" y="80" class="l">regional prices, review</text>
<text x="14" y="98" class="l">screenshots, testers</text>
<rect x="14" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="31" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
<rect x="54" y="116" width="30" height="20" rx="10" fill="#451a03"/><text x="69" y="130" class="tg" fill="#fcd34d" text-anchor="middle">UI</text>
</g>
<!-- 4 listings -->
<g transform="translate(586 104)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">4</text>
<text x="42" y="29" class="tt">Listings</text>
<text x="14" y="62" class="l">name, subtitle, texts,</text>
<text x="14" y="80" class="l">keywords, contact, in</text>
<text x="14" y="98" class="l">every language</text>
<rect x="14" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="31" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
</g>
<!-- 5 questionnaires -->
<g transform="translate(772 104)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">5</text>
<text x="42" y="29" class="tt">Questionnaires</text>
<text x="14" y="62" class="l">Data safety, age rating,</text>
<text x="14" y="80" class="l">encryption · IARC, target</text>
<text x="14" y="98" class="l">audience, App Privacy</text>
<rect x="14" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="31" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
<rect x="54" y="116" width="30" height="20" rx="10" fill="#451a03"/><text x="69" y="130" class="tg" fill="#fcd34d" text-anchor="middle">UI</text>
</g>
<!-- 6 privacy & icons -->
<g transform="translate(28 314)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">6</text>
<text x="42" y="29" class="tt">Privacy &amp; icons</text>
<text x="14" y="62" class="l">policy page, privacy</text>
<text x="14" y="80" class="l">manifest scan, every</text>
<text x="14" y="98" class="l">icon from one artwork</text>
<rect x="14" y="116" width="46" height="20" rx="10" fill="#0c4a6e"/><text x="37" y="130" class="tg" fill="#7dd3fc" text-anchor="middle">LOCAL</text>
</g>
<!-- 7 store art -->
<g transform="translate(214 314)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">7</text>
<text x="42" y="29" class="tt">Store art</text>
<text x="14" y="62" class="l">screenshots, previews,</text>
<text x="14" y="80" class="l">feature graphic: render,</text>
<text x="14" y="98" class="l">check, upload</text>
<rect x="14" y="116" width="46" height="20" rx="10" fill="#0c4a6e"/><text x="37" y="130" class="tg" fill="#7dd3fc" text-anchor="middle">LOCAL</text>
<rect x="66" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="83" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
</g>
<!-- 8 validate -->
<g transform="translate(400 314)">
<rect class="box" width="160" height="150" rx="12"/>
<circle cx="22" cy="24" r="13" fill="#e2e8f0"/><text x="22" y="28.5" class="n" text-anchor="middle">8</text>
<text x="42" y="29" class="tt">Validate</text>
<text x="14" y="62" class="l">offline check, then a</text>
<text x="14" y="80" class="l">read-only store report:</text>
<text x="14" y="98" class="l">blockers in fix order</text>
<rect x="14" y="116" width="34" height="20" rx="10" fill="#14532d"/><text x="31" y="130" class="tg" fill="#86efac" text-anchor="middle">API</text>
<rect x="54" y="116" width="46" height="20" rx="10" fill="#0c4a6e"/><text x="77" y="130" class="tg" fill="#7dd3fc" text-anchor="middle">LOCAL</text>
</g>
<!-- 9 you press submit -->
<g transform="translate(586 314)">
<rect width="346" height="150" rx="12" fill="#3b0a24" stroke="#db2777" stroke-width="1.5"/>
<circle cx="22" cy="24" r="13" fill="#f9a8d4"/><text x="22" y="28.5" class="n" text-anchor="middle">9</text>
<text x="42" y="29" class="tt">You press Submit</text>
<text x="14" y="62" class="l">Play Console: Send changes for review</text>
<text x="14" y="80" class="l">App Store Connect: Submit for Review</text>
<text x="14" y="98" class="l">Releases and rollouts after approval stay yours too.</text>
<rect x="14" y="116" width="38" height="20" rx="10" fill="#500724"/><text x="33" y="130" class="tg" fill="#f9a8d4" text-anchor="middle">YOU</text>
</g>
<!-- legend -->
<g transform="translate(28 498)">
<rect x="0" y="0" width="34" height="20" rx="10" fill="#14532d"/><text x="17" y="14" class="tg" fill="#86efac" text-anchor="middle">API</text>
<text x="42" y="14.5" class="lg">storebound command</text>
<rect x="178" y="0" width="30" height="20" rx="10" fill="#451a03"/><text x="193" y="14" class="tg" fill="#fcd34d" text-anchor="middle">UI</text>
<text x="216" y="14.5" class="lg">console only: a skill walks your agent (or you) through it</text>
<rect x="562" y="0" width="46" height="20" rx="10" fill="#0c4a6e"/><text x="585" y="14" class="tg" fill="#7dd3fc" text-anchor="middle">LOCAL</text>
<text x="616" y="14.5" class="lg">your machine</text>
<rect x="718" y="0" width="38" height="20" rx="10" fill="#500724"/><text x="737" y="14" class="tg" fill="#f9a8d4" text-anchor="middle">YOU</text>
<text x="764" y="14.5" class="lg">your click</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.6 KiB

View file

@ -1,7 +1,7 @@
{ {
"name": "storebound", "name": "storebound",
"version": "0.3.0", "version": "0.3.1",
"description": "Ship mobile games to Google Play and the App Store: store listings, in-app products, data safety, screenshots, icons, release management and review checklists, as Agent Skills plus a Bun CLI and MCP server (storebound). CRTkafa's own toolchain, open-sourced.", "description": "From nothing to Submit for review on Google Play and the App Store: app records, listings in every language, in-app products with regional prices, every questionnaire (Data safety, IARC, target audience, ads, App Privacy, age rating, export compliance), privacy, icons, screenshots and previews, validate, release management. Agent Skills plus a Bun CLI and MCP server (storebound); you press Submit. CRTkafa's own toolchain, open-sourced.",
"contextFileName": "GEMINI.md", "contextFileName": "GEMINI.md",
"mcpServers": { "mcpServers": {
"storebound": { "storebound": {

View file

@ -1,7 +1,7 @@
{ {
"name": "storebound", "name": "storebound",
"version": "0.3.0", "version": "0.3.1",
"description": "My toolchain for shipping mobile games to Google Play and the App Store: a Bun CLI, an MCP server and Agent Skills for any AI coding tool.", "description": "Take a mobile game from nothing to Submit for review on Google Play and the App Store: app records, listings in every language, in-app products with regional prices, every store questionnaire, privacy, icons, screenshots and previews. One config, a Bun CLI, an MCP server and Agent Skills for your AI coding agent.",
"license": "MIT", "license": "MIT",
"author": "CRTkafa", "author": "CRTkafa",
"type": "module", "type": "module",

View file

@ -48,14 +48,14 @@ export function generate(root: string): Map<string, string> {
const out = new Map<string, string>(); const out = new Map<string, string>();
const homepage = 'https://git.crt.fyi/CRT/storebound'; const homepage = 'https://git.crt.fyi/CRT/storebound';
const repository = 'https://git.crt.fyi/CRT/storebound.git'; const repository = 'https://git.crt.fyi/CRT/storebound.git';
const description = 'Ship mobile games to Google Play and the App Store: store listings, in-app products, data safety, screenshots, icons, release management and review checklists, as Agent Skills plus a Bun CLI and MCP server (storebound). CRTkafa\'s own toolchain, open-sourced.'; const description = 'From nothing to Submit for review on Google Play and the App Store: app records, listings in every language, in-app products with regional prices, every questionnaire (Data safety, IARC, target audience, ads, App Privacy, age rating, export compliance), privacy, icons, screenshots and previews, validate, release management. Agent Skills plus a Bun CLI and MCP server (storebound); you press Submit. CRTkafa\'s own toolchain, open-sourced.';
const keywords = ['google-play', 'app-store', 'app-store-connect', 'mobile-games', 'iap', 'screenshots', 'app-icons', 'release', 'aso', 'mcp']; const keywords = ['google-play', 'app-store', 'app-store-connect', 'mobile-games', 'iap', 'screenshots', 'app-icons', 'release', 'aso', 'mcp'];
// 1. Claude Code plugin + its MCP server + marketplace // 1. Claude Code plugin + its MCP server + marketplace
out.set('.claude-plugin/plugin.json', json({ name: 'storebound', version: pkg.version, description, author: { name: 'CRTkafa' }, homepage, repository, license: pkg.license, keywords })); out.set('.claude-plugin/plugin.json', json({ name: 'storebound', version: pkg.version, description, author: { name: 'CRTkafa' }, homepage, repository, license: pkg.license, keywords }));
out.set('.mcp.json', json({ mcpServers: { storebound: { command: '${CLAUDE_PLUGIN_ROOT}/bin/storebound', args: ['mcp'] } } })); out.set('.mcp.json', json({ mcpServers: { storebound: { command: '${CLAUDE_PLUGIN_ROOT}/bin/storebound', args: ['mcp'] } } }));
out.set('.claude-plugin/marketplace.json', json({ name: 'crtkafa', description: 'CRTkafa\'s open-sourced tools.', owner: { name: 'CRTkafa' }, out.set('.claude-plugin/marketplace.json', json({ name: 'crtkafa', description: 'CRTkafa\'s open-sourced tools.', owner: { name: 'CRTkafa' },
plugins: [{ name: 'storebound', source: '.', description: 'Ship mobile games to Google Play and the App Store: skills for every store step plus the storebound CLI and MCP server.', plugins: [{ name: 'storebound', source: '.', description: 'Take a mobile game from nothing to Submit for review on both stores: skills for every store step and questionnaire plus the storebound CLI and MCP server.',
version: pkg.version, category: 'development', tags: ['mobile', 'google-play', 'app-store', 'release'] }] })); version: pkg.version, category: 'development', tags: ['mobile', 'google-play', 'app-store', 'release'] }] }));
// 2. OpenAI Codex plugin (skills; MCP via `storebound install --agent codex`) // 2. OpenAI Codex plugin (skills; MCP via `storebound install --agent codex`)