A shared harness for shipping one product on iOS and Android:
- One Homebrew install, one
appkit.jsonmanifest per repo. - Skip Xcode and App Store Connect for your day-to-day screenshot workflow. Xcode and ASC are bulky, you better not opening them :)
- No Simulator or manual screenshots. Generate App Store screenshots with one command.
- Deterministic outputs. Same input, same screenshots—
git difftells you exactly what changed. - Zero commands to memorize. One-time setup, sensible defaults, customize only when you want to.
brew tap walkccc/appkit https://github.com/walkccc/appkit
brew install --HEAD appkit
appkit skills # once per machine — links the /appkit-… skills into ~/.claude/skillsappkit does not create the app — Xcode and Android Studio do that. It creates the pipeline around it: the manifest, the screenshot mode's contract, the ASC listing metadata, the house style.
- Create the project: Xcode ▸ File ▸ New ▸ Project (name
MyApp, bundlecom.example.MyApp) for iOS, or Android Studio ▸ New Project (name + package) for Android. This makes the repo folder — I like to name itmyapp-ios/myapp-androidto keep it apart from a web repo of the same product. - Scaffold the pipeline from inside it:
or run
appkit new ios --name MyApp --bundle com.example.MyApp --locales "en zh-Hant ja" appkit new android --name MyApp --package com.example.myapp --locales "en ja"
/appkit-scaffold, which is the same call with the judgement calls attached. It does not touch screenshots — that comes later, once there is an app to take them of. - Build the app. This is the product; appkit has nothing to do here.
/appkit-add-screenshots-modewires the debug-only screenshot mode into it —-ScreenshotSceneon iOS,-e screenshotSceneon Android, read off the launch, seeding each scene's data and freezing anything withrepeatForever. Thenappkit make screenshotsand look at what came out.- Make the store record, then pull and fill in
store/metadata—/appkit-metadata, through toappkit doctor && appkit check metadata. /appkit-releasefor everything after: the version bump, the real screenshot set, the listing upload, andappkit ship.
A second platform for a product already on the kit is the same appkit new call, in its own sibling repo — it never overwrites without --force.
appkit help # what any of these do (appkit help VERB for one)
appkit new ios # scaffold a repo, from nothing
appkit sync # write this repo's shared files
appkit doctor # check they stayed put
appkit run # build, install, launch
appkit capture # photograph the store scenes, one launch each
appkit render # compose them into store cards
appkit make screenshots # capture + render, and stop
appkit check metadata # every store's limits, every language's coverage
appkit pull metadata # what the listing says right now, to compare
appkit upload metadata # the listing text, onto the store
appkit upload screenshots # the store cards, onto the store
appkit ship # the binary, onto the store
appkit version 1.3.0 # move the version everywhere it is written| A repo owns | appkit syncs in, and doctor checks |
|---|---|
appkit.json — platform, locales, scenes, ids |
AGENTS.core.md — the house style |
scripts/scenes.sh — what a screenshot IS |
.prettierrc, .swiftformat (iOS) |
store/ — the storyboard, the words, the cards |
.githooks/pre-commit, .gitignore's block |
Everything appkit hands a repo is a copy, never a symlink — a link survives neither an upgrade nor another machine. appkit sync writes it, appkit doctor fails on any difference, so an upgrade reaches a repo as a reviewable diff, not silently. A repo that genuinely extends a shared file declines it instead of drifting: "sync": { "skip": [".prettierrc"] }.
A locale, a scene name or a store folder written into a script is drift — all three are rows in appkit.json, and every command reads them from there.
appkit skills links these into ~/.claude/skills, once per machine — the
command is the mechanism, the skill is the judgement a script can't make:
| Skill | For |
|---|---|
/appkit-scaffold |
standing up a new repo, or a second platform for one |
/appkit-add-screenshots-mode |
wiring the debug-only screenshot mode into an app that doesn't have it yet |
/appkit-screenshots |
adding a scene, mixing in a widget or the watch, or debugging a set that will not reproduce |
/appkit-metadata |
writing the listing text — every field, every language |
/appkit-release |
shipping end to end, in order, knowing what's reversible |
- Design tokens. The shape is shared, in a paragraph of
AGENTS.core.md; the values never are — the same token name has meant three different values across the repos this came from. .editorconfig. Ships inconfig/to copy by hand, not to sync: it carries a language's indent and lint rules, which are the repo's own.- An illustrated card set, or a site's own OG pipeline. A repo whose cards are drawn rather than composed keeps its own renderer, declared as
render.commandinappkit.json.
appkit/
├── AGENTS.core.md the house style, copied into every app
├── bin/appkit the entry point: one verb per command, and appkit help
├── commands/ one file per subject — capture, render, upload, metadata, …
├── lib/ manifest, log + shutter, sharding, the picture gate
├── platform/ ios.sh, android.sh — the device contract
├── render/ compose.swift, same-picture.swift, fonts/, bezels/
├── store/ asc.sh, play.sh, metadata.sh — the store adapters
├── skills/ agent instructions, linked into ~/.claude/skills
├── config/ .swiftformat, .prettierrc, .editorconfig, gitignore.base
├── githooks/ pre-commit
├── templates/ cards.json
├── docs/CARDS.md the card storyboard schema
├── Formula/ the brew formula
└── VERSION what doctor checks a repo's floor against
macOS and Homebrew, plus what your platform needs: Xcode for iOS, the Android SDK for Android. Otherwise bash, python3, swiftc, curl and openssl — all already on a Mac with the Xcode command line tools. Publishing to the App Store also needs asc (brew install asc); appkit says so when it needs it. The composer is macOS-only — CoreText is why it lays out Japanese and Korean beside Latin without a font per script.
CONTRIBUTING.md. The bar is "is this true of every app on appkit" — if it's true of one platform it belongs in platform/, and if it's true of one app it belongs in that app.
MIT — LICENSE. The vendored Poppins is under the SIL Open Font Licence (render/fonts/OFL.txt).