Demo apps
The fastest path from nothing to a working product: three demo apps ship as DECLARATIVE SPECS (tools/lib/demos.mjs), not templates. The codegen (tools/lib/demo-codegen.mjs) turns a spec into real code inside a freshly scaffolded app, for either db variant: the schema block (Convex schema.ts table / Supabase SQL table with RLS), a CRUD backend module, select-option constants, and an EntityConfig-driven multi-view page, registered in src/features/index.tsx. A --demo app replaces the example/records placeholders — every other feature stays available.
pnpm new my-crm --demo crm # Mini CRM (pipeline board, revenue stats)
pnpm new my-app --demo tasks --db supabase # Task Board on the SQL variant
pnpm new my-shop --demo catalog --features mcp # Product Catalog + MCP server
pnpm new my-app --demo ./my-spec.json # community spec file
The three demos at a glance
- crm — Mini CRM: contacts (name, company, email, stage select [lead/qualified/proposal/won/lost], dealValue number, closeDate date, tags, notes) + a second activities entity (summary, contact, kind select, when date, notes). Board = pipeline, stats = revenue, calendar = follow-ups.
- tasks — Task Board: tasks (title, status select [backlog/doing/review/done], priority select, assignee, dueDate, estimate number, tags, notes). Board = workflow, calendar = deadlines, stats = throughput.
- catalog — Product Catalog: products (name, sku, category select [general/featured/sale/archived], price number, stock number, restockDate date, imageUrl image, tags, notes). Gallery = showroom, table = inventory, stats = stock value.
A demo has one or more entities; the FIRST is primary — it gets the demo's id as its feature id and is the target of --fields/--table/--labels. Extra entities (like the CRM's activities) use their table name as the feature id.
Seed data and the "Load sample data" button
Each entity can carry seed rows (crm: 6 contacts + 3 activities; tasks: 6; catalog: 6). When the workspace is empty, the generated page shows a "Load sample data" button. On Convex it calls a generated seedDemo mutation (idempotent — it inserts nothing if rows already exist); on Supabase it inserts the generated <TABLE>_SEED constant for the signed-in user. Seed rows are completed with the same defaults create() applies (first select option, empty tags, false booleans).
MCP tools (when the mcp feature is on)
With the mcp feature (implies api-keys), each generated entity is wired into the app's MCP server with tools named from its labels: list_<plural> (the user's rows, newest first), create_<singular> (takes the title field), and — if the entity has a select statusKey — set_<singular>_<statuslabel> (e.g. set_contact_stage, set_task_status, set_product_category) which validates the value against the select's options. On Convex these ride generated internal apiList/apiCreate/apiSetStatus functions; on Supabase they are added to the functions/mcp Edge Function.
Defaults per demo
Each demo picks a sensible design/accent/layout, all overridable with the normal flags: crm = saas · blue · sidebar; tasks = dashboard · violet · header; catalog = minimal · teal · sidebar. --demo always builds a --type webapp on the react stack, and defaults --features to everything except the example/records placeholders.
Reshaping and renaming
# reshape fields — backend AND frontend follow the spec:
pnpm new my-crm --demo crm --fields "+source:select:Lead source,-notes"
# rename the primary table + its labels (the demo-eject move):
pnpm new my-crm --demo crm --table clients --labels "Client,Clients"
See pnpm new for the full --fields/--table/--labels semantics — the same --fields syntax also works WITHOUT --demo, reshaping the generic records baseline. The scaffolder writes a .demo.json manifest into the app; pnpm smoke uses it to drive a generated-domain round-trip.
The generated code is yours — plain schema + CRUD + one CONFIG, in the same shape as the records pattern. Edit it directly, or re-scaffold with different flags while you are still exploring.