Skip to content

Repository files navigation

appkit

A shared harness for shipping one product on iOS and Android:

  • One Homebrew install, one appkit.json manifest 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 diff tells you exactly what changed.
  • Zero commands to memorize. One-time setup, sensible defaults, customize only when you want to.

Install

brew tap walkccc/appkit https://github.com/walkccc/appkit
brew install --HEAD appkit
appkit skills   # once per machine — links the /appkit-… skills into ~/.claude/skills

Getting started

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

  1. Create the project: Xcode ▸ File ▸ New ▸ Project (name MyApp, bundle com.example.MyApp) for iOS, or Android Studio ▸ New Project (name + package) for Android. This makes the repo folder — I like to name it myapp-ios / myapp-android to keep it apart from a web repo of the same product.
  2. Scaffold the pipeline from inside it:
    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"
    or run /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.
  3. Build the app. This is the product; appkit has nothing to do here.
  4. /appkit-add-screenshots-mode wires the debug-only screenshot mode into it — -ScreenshotScene on iOS, -e screenshotScene on Android, read off the launch, seeding each scene's data and freezing anything with repeatForever. Then appkit make screenshots and look at what came out.
  5. Make the store record, then pull and fill in store/metadata/appkit-metadata, through to appkit doctor && appkit check metadata.
  6. /appkit-release for everything after: the version bump, the real screenshot set, the listing upload, and appkit 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.

Commands

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

What's yours, what's appkit's

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.

Skills

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

What it does not share

  • 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 in config/ 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.command in appkit.json.

Layout

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

Requirements

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

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.

Licence

MIT — LICENSE. The vendored Poppins is under the SIL Open Font Licence (render/fonts/OFL.txt).