Appearance
Scaffolding an app
Detailed reference for the app-platform apps init step of the app-creator skill (Step 1).
The command
bash
mkdir -p <parent-dir>
bunx app-platform apps init <app-name> --template <template> --output-dir <parent-dir> --include-skill --blank
cd <parent-dir>/<app-name> && bun install<app-name>— short kebab-case name derived from the user's prompt (e.g. "a voting app" →voting-app).<parent-dir>— directory the new app folder will be created inside. The CLI errors out if<parent-dir>/<app-name>already exists.--template <template>— one ofreact,preact,solidjs,vanilla-js. Prefervanilla-jsorpreactfor simplicity; only usereactorsolidjsif the prompt specifically needs them.--include-skill— copies the SDK's bundled skills (app-creator,synced-store,poe-app) into<app-dir>/.claude/skills/so Claude Code inside the new checkout has them available locally.--blank— replaces the todo-list example with empty stubs. Always pass this (see below).
Why --blank is mandatory
Without --blank, the scaffold writes a working todo-list app you'd have to delete and rewrite. With --blank you get the same boilerplate (package.json, vite config, tsconfig.json, biome, index.html, styles.css) but these files are empty stubs:
synced-store/schema.ts—appSchemawithtables: {}/mutators: {}synced-store/mutators.ts—appMutators: InferMutatorHandlers<AppSchema> = {}synced-store/client-config.tsandbackend-config.ts— wire the empty schema/mutatorsclient.ts— re-exportsappSchema/AppSchema/AppStoreClient/appClientConfig/appMutatorsui/App.{tsx,ts}— hello-world stubsynced-store/mutators.test.ts,ui/App.test.happydom.tsx—test.todo()placeholders (colocated with their source)tests/e2e.test.playwright.ts— single page-loads smoke
Day-zero bun run type-check / test / build / test:playwright all pass on the empty skeleton — no half-converted broken state while you write your real code.
Do not pass --committed
--committed is a flag for use inside the Poe app-platform monorepo. It rewrites poe-apps-sdk to workspace:* (which won't resolve outside the monorepo), pins zod to a version your project may not have, and emits a tsconfig.json that extends a parent which doesn't exist. Outside the monorepo, leave it off.
Reference app — scaffold a sibling, read it, then delete it
The blank stubs use generic names (appSchema, appMutators, AppStoreClient, appClientConfig, appBackendConfig). To see a worked example, re-scaffold a sibling directory without --blank, read it, then delete it:
bash
bunx app-platform apps init reference-todo --template <same-template> --output-dir /tmp
# read /tmp/reference-todo/synced-store/, /tmp/reference-todo/ui/, /tmp/reference-todo/tests/Note the patterns; don't copy code blindly — your schema is yours.
Templates
Four templates are available: react, preact, solidjs, vanilla-js. Running app-platform apps init without --template prompts interactively. All templates use the poeApp() vite plugin and ship with the same boilerplate (package.json, vite, tsconfig, biome, index.html, styles.css). Without --blank, the scaffold writes a working todo-list example (synced-store schema, mutator tests, playwright E2E tests). With --blank, that example is replaced by stubs as listed above. The --blank and non-blank scaffolds are identical apart from the contents of the stubbed files.
Generated files (after scaffolding)
After bunx app-platform apps init ... && bun install finishes, the new directory contains:
<app-name>/
├── app/ # entry point + backend wiring
│ └── src/
│ ├── entry.tsx # calls Poe.setupStore(clientConfig); renders UI
│ └── backend.ts # re-exports appBackendConfig as default
├── synced-store/ # store contract
│ ├── schema.ts
│ ├── mutators.ts
│ ├── mutators.test.ts # colocated unit tests
│ ├── client-config.ts
│ └── backend-config.ts
├── ui/ # store-agnostic components (receive `store` via props)
│ ├── App.{tsx,ts}
│ └── App.test.happydom.tsx # colocated UI tests
├── tests/ # e2e (Playwright) + setup-dom helper
├── scripts/
│ └── doctor.sh # toolchain health check (used by Step 0)
├── client.ts # client-safe re-exports
├── package.json
├── tsconfig.json
├── vite.config.ts
└── playwright.config.tsThe scripts/doctor.sh script is what the agent runs in Step 0 of the parent skill before scaffolding anything new — once the app is scaffolded, the same script is available inside the app for re-running on demand.