Walkthrough — from zero to running app
We’re going from nothing to a running Kumiko app with one custom feature. Three commands, one file to edit, ~5 minutes.
At the end you have:
- a fresh app workspace under
./my-notes/ - one feature
noteswith an entity and a starter handler - a clean boot:
[runProdApp] boot validation OK
Prerequisite: Bun ≥ 1.2.20. Postgres + Redis are NOT required for the boot-validation path used here.
Step 1 — Scaffold the app
Section titled “Step 1 — Scaffold the app”bunx @cosmicdrift/kumiko-cli new app my-notescd my-notesbun installThis creates package.json, tsconfig.json, src/run-config.ts, bin/main.ts, .env.example, README.md. No mkdir, no hand-typed config.
src/run-config.ts already mounts secrets + sessions as foundation. config, user, tenant, and auth-email-password are auto-mounted by composeFeatures because bin/main.ts passes auth: { admin: { … } }.
Step 2 — Add your first feature
Section titled “Step 2 — Add your first feature”bunx @cosmicdrift/kumiko-cli add feature notesThis creates src/features/notes/feature.ts and src/features/notes/index.ts, and auto-mounts the feature in src/run-config.ts:
import { notesFeature } from "./features/notes";
export const APP_FEATURES = [ createSecretsFeature(), createSessionsFeature(), notesFeature,] as const;You never edit run-config.ts by hand — the CLI does it via ts-morph.
Step 3 — Configure env + boot
Section titled “Step 3 — Configure env + boot”cp .env.example .envEdit .env and set:
JWT_SECRET=$(openssl rand -base64 32)KUMIKO_SECRETS_MASTER_KEY_V1=$(openssl rand -base64 32)Then boot:
bun run bootExpected output:
[runProdApp] booting Kumiko stack on port 3000…[runProdApp] boot validation OK (7 features, 7 registry entries)That’s the boot-validation path (KUMIKO_DRY_RUN_ENV=boot): every feature mounted, every r.requires resolved, every entity schema validated — without touching DB or Redis. The 7 features = 3 you mounted (secrets, sessions, notes) + 4 auto-prepended (config, user, tenant, auth-email-password, because bin/main.ts passes auth: { admin: { … } }). The next step would wire real services, but everything above this line is already working.
What just happened
Section titled “What just happened”| File | What it does |
|---|---|
src/run-config.ts | Single source of truth: which features your app mounts. |
bin/main.ts | Production bootstrap. Reads env, calls runProdApp({ features, auth, … }). |
src/features/notes/feature.ts | Your defineFeature("notes", (r) => …) body. Add entities, write/query handlers, hooks. |
Edit your feature
Section titled “Edit your feature”Open src/features/notes/feature.ts. It looks like this:
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
export const notesFeature = defineFeature("notes", (r) => { r.entity("notes-item", { fields: { title: { type: "text", required: true }, }, });});Add a body field and a pinned flag:
r.entity("notes-item", { fields: { title: { type: "text", required: true }, body: { type: "text" }, pinned: { type: "boolean", default: false }, },});Re-run bun run boot to validate: the schema still composes cleanly.
Next steps
Section titled “Next steps”- Add a write handler with
r.writeHandler(...)— see Patterns for ther.*API. - Add a query handler with
r.queryHandler(...)to read your data. - Wire screens + nav for an admin UI (
r.screen,r.nav). - Pull in bundled features —
audit,delivery,cap-counter,subscription-stripe, … — by editingsrc/run-config.ts. (Or scaffold your own withbunx @cosmicdrift/kumiko-cli add feature <name>.)
Why this is different
Section titled “Why this is different”The previous walkthrough required you to mkdir, hand-write package.json, hand-write tsconfig.json, hand-mount features in run-config.ts. Each step was a chance to mistype something. The new path:
- 3 commands, 0 hand-typed config
defineFeature(...)is the only place a feature’s name lives- Boot is one command, validates everything, fails fast with a clear error
If you hit something that doesn’t work as described, open an issue.