Two follow-ups to8cd5805: - CLAUDE.md's "Crema system" section now points at docs/LIBS.md (the generated catalog) as the primary lookup. Live manifest reference moved below as a fallback. Keeps the LLM's first hit at a compact, alpha-sorted table instead of the live JSON. - The .boot.log file (created by my fresh-clone integration test) was accidentally committed in8cd5805. Remove from tracking and ignore going forward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
crema-app-aifirst-template
Minimal hybrid traditional + AI-first webapp scaffold built on the
Crema design system. Sibling to
crema-app-template
(the bare scaffold) — this template adds the AI assistant surface, the
command bus, scripts, and a virtual cursor.
The pitch: most surfaces are normal (sidenav, tables, forms) and an Assistant surface where the LLM can actually drive the UI on the user's behalf — click, navigate, fill, submit — through a documented command bus that scripts and remote control share.
Quick start
npm install
npm run dev
Open http://localhost:5173. The app probes a local
LM Studio at http://localhost:1234/v1 and falls back to a MockLLM if it
can't reach one — the UI is always usable.
To use the Assistant with a real model:
- Run LM Studio (or any OpenAI-compatible local server — Ollama, vLLM, etc.). Enable CORS in its server settings.
- Visit
/settingsand confirm the base URL. - Visit
/assistantand click Enable UI Control. - Type "take me to settings" — watch the cursor.
What this template gives you
App shell
app/components/layout/app-shell.tsx. Collapsible left rail (icon-only ↔
expanded with labels, persisted), top appbar (search · scripts · theme · bell
· avatar dropdown), mobile sheet at <md. Brand and user identity come from
app/lib/identity.ts — swap useBrand() / useUser() for a real session
later. Skip-to-main-content link, focus rings, [data-action] slots
throughout. The shell is template code, not a lib — fork it, customize
it, no need to upgrade an upstream.
AI assistant with UI control
/assistant route. Streams from any OpenAI-compatible LLM via
@crema/llm-ui, with mock
fallback. Message bubbles render markdown, fenced ```action blocks in the
model's reply are extracted and run through the command bus. Status bar,
model selector, token meter, retry probe, stop-while-streaming, persistent
UI Control toggle.
Command bus + DSL + virtual cursor
Provided by @crema/action-bus.
JSON commands dispatch to handlers; producers are LLM tool calls, scripts,
and (optional) WebSocket — all funnel through one bus.
window.commandBus.dispatch({ type: "navigate", path: "/resources" })
window.commandBus.listActions() // every visible [data-action] on screen
Plus a plain-text DSL for humans / LLM:
navigate /resources
wait_for resources-table
click row-acme-corp
expect detail-panel to_contain "Acme"
Hit ⌘⇧P for the script runner dialog. See docs/AI_FIRST.md for the full system tour.
Mightypix theme
Default theme is lib-theme-mightypix —
warm cream surfaces, ink-blue accent, Source Serif 4 for assistant prose.
Swap by editing one @import line in app/app.css. Per-route alt themes
via <AppShell theme="…">. See app/components/layout/THEME_CONTRACT.md.
Sibling-cloning
Crema libs are sibling git repos, not npm packages. Before npm install
you need them cloned alongside this template:
your-workspace/
crema-app-aifirst-template/ ← this repo
lib-action-bus/
lib-aifirst-ui/
lib-chat-ui/
lib-llm-ui/
lib-notification-ui/
lib-theme-mightypix/
Use the crema add CLI from
create-crema-app,
or clone manually. tsconfig paths and app.css @source lines are
pre-wired.
Structure
app/
routes/ # 6 routes: Overview, Resources, Activity, Assistant, Library, Settings
components/
layout/ # AppShell, Appbar, ThemeToggle, THEME_CONTRACT.md
assistant/ # MessageBody (markdown + action-block pill)
scripts-dialog.tsx # ⌘⇧P script runner UI
ui/ # shadcn primitives
lib/
identity.ts # useBrand() / useUser() — swap for real session
llm-settings.ts # persisted base URL / context / response cap
page-meta.ts # `pageTitle("…")` for route <title>
utils.ts # shadcn `cn()`
app.css # active theme @import + tailwind + @source lines
root.tsx # ToastProvider + CommandBusProvider
public/
scripts/
demo-tour.script # sample DSL: tour the rail
demo-search.script # sample DSL: focus + fill search
docs/
AI_FIRST.md # full system tour
Dev scripts
| Command | What it does |
|---|---|
npm run dev |
Vite dev server |
npm run build |
Production build |
npm run start |
Serve the built app |
npm run typecheck |
react-router typegen && tsc |
bash start.sh / bash stop.sh |
Run dev server in the background, log to .demo.log |
Conventions to know
[data-action="<id>"]on every interactive element — turns it into something the LLM, scripts, and tests can target. Naming:nav-*,appbar-*,avatar-*,assistant-*,settings-*, etc.- Tokens, not values.
bg-card,text-foreground,var(--primary)— never hex. - Lib-shaped components live as sibling repos. Edits commit to the lib's
own repo. See
CLAUDE.mdfor polyrepo gotchas.
Further reading
docs/AI_FIRST.md— full system tourapp/components/layout/THEME_CONTRACT.md— token contractCLAUDE.md— orientation for an LLM working in this repo
What's not in here
- Real auth —
useUser()returns a static stub - Real backend —
/resources,/activity,/libraryare placeholder routes - Production safety gates around LLM-driven actions —
[data-action-danger]and confirmation flows are sketched indocs/AI_FIRST.mdbut not built
These are deliberate. The template is the framework; domain content is what you add.