0.3.1: README around the zero-to-Submit journey, journey diagram, new positioning in package and plugin descriptions
This commit is contained in:
parent
c43c20f370
commit
74dbf8f5a6
9 changed files with 289 additions and 82 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -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
181
README.md
|
|
@ -1,59 +1,71 @@
|
||||||
# storebound
|
# storebound
|
||||||
|
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
[](https://bun.sh)
|
[](https://bun.sh)
|
||||||
[](package.json)
|
[](package.json)
|
||||||
[](skills)
|
[](skills)
|
||||||
[](#mcp-server)
|
[](#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
|

|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||

|
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
|
||||||
|  |  |
|
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.
|
||||||
|
|
||||||

|
| # | 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.
|
||||||
|
|
||||||

|
### 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
| Play feature graphic | App preview (App Store, 886 x 1920) |
|
||||||
|
|---|---|
|
||||||
|
|  |  |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Contact sheet of one language (every size, packed into a grid)</summary>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
</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
153
docs/img/journey.svg
Normal 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 & 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 |
|
|
@ -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": {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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`)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue