Contributing
Prerequisites
- Bun, package manager and runtime (not npm/yarn).
run.shauto-installs it on first run if missing. - Ollama, the app can install/manage it, but having it running locally helps.
- ComfyUI is installed by the app itself (it manages a Python runtime), no manual setup needed for image-gen work.
Running
./run.sh # macOS/Linux — production (build the UI, serve everything on :3000)./run.sh --dev # dev servers + HMR (Vite on :5173, hot-reloading backend on :3000)On Windows use .\run.ps1 / .\run.ps1 -Dev (siblings with the same behavior).
The launcher installs Bun if absent, stops any previous instance and its detached
sidecars, refreshes dependencies when the lockfile changed, opens the browser, and
then supervises the servers — a crashed backend/frontend is auto-restarted
(capped 5×/5 min). On exit it sweeps sidecars but leaves ollama serve running so
the next launch is instant. --uninstall / -Uninstall removes app data, models,
and ComfyUI/Ollama after a typed confirmation.
See /dev/launcher for the full launch sequence, flags, the
auto-restart loop, the Windows GPU brownout guard, and eGPU recovery.
The two dev servers can also be run by hand:
cd backend && bun run dev # bun run --hot src/index.tscd frontend && bun run dev # viteThere is no automated test suite. The bar for “done” is that both builds pass.
Build Verification
After any frontend change:
cd frontend && bun run build # tsc -b && vite buildAfter any backend change:
bun build --target=bun backend/src/index.tsBoth must exit 0 before a change is done. Never rely on tsc --noEmit alone, Vite’s transform catches additional JSX/TSX errors that TypeScript misses.
Code Conventions
Frontend
- Use
cn()from@/lib/cnfor all className composition (clsx + tailwind-merge) - Accent color: always
bg-brand,text-brand,border-brand,ring-brand, neverviolet-500or theprimarytoken - Icons:
lucide-reactonly, do not add other icon libraries - Components in
shared/: extend before duplicating; updateagents.mdcatalog when adding
Backend
- Use
bun:sqlite(not better-sqlite3 or node:sqlite) via Drizzle (backend/src/db/schema.ts) - Schema changes: edit
schema.tsand mirror an idempotent statement inrunMigrations()(backend/src/db/index.ts). Do not rely ondrizzle-kit generate - Proxy all AI calls, keys and Ollama URLs never reach the browser
- Add
think: falseto every Ollama request body - Guard routes with
requireAuth(orrequireAdmin) frombackend/src/middleware/auth.ts
SSE Streaming
- Use Hono’s
streamSSEhelper - Chat token handler must replace the entire
messagesarray, components in the message list must be wrapped inReact.memo
Architecture Decisions
See /dev/architecture for the full system overview.
When to use /plan before starting:
- Architecture changes
- Large refactors
- New subsystems
- Database schema changes
- API redesigns
Stay in execution mode for bug fixes, small features, and documentation.