Hybrid traditional + AI-first webapp scaffold. Sibling to crema-app-template, adds the AI assistant surface, command bus, scripts dialog, and virtual cursor. What's pre-wired: - 6 routes: Overview, Resources, Activity, Assistant, Library, Settings - Collapsible rail + appbar + avatar dropdown shell (template code, not a lib) - Mobile sheet at <md - /assistant: streaming chat via @crema/llm-ui, mock fallback, model selector, token meter, retry probe, stop-while-streaming, persistent UI Control toggle - /settings: editable LM Studio endpoint + context window + response cap, with test-connection button - Markdown rendering for assistant replies; ```action``` blocks rendered as a small "Ran N actions" pill - ⌘⇧P script runner dialog + Play icon in the appbar - Two demo scripts in public/scripts/ - mightypix theme as default, scoped via <AppShell theme="mightypix"> Libs wired in tsconfig + app.css: - @crema/action-bus (the bus, parser, runner, cursor, provider, ws, llm-bridge) - @crema/llm-ui, @crema/chat-ui, @crema/aifirst-ui, @crema/notification-ui - lib-theme-mightypix Docs: - README.md — pitch + quick start + structure - docs/AI_FIRST.md — full system tour (data-action contract, bus, DSL, scripts, cursor, LLM integration) - app/components/layout/THEME_CONTRACT.md — every CSS variable a theme must declare - CLAUDE.md — orientation for an LLM working in the repo Genericized from comfy-cloud (the original prototype): - Brand defaults to "App" / Sparkles icon (override via app/lib/identity.ts) - User defaults to a stub (swap useUser() for real auth) - localStorage namespace is "crema.*" (was "comfy.*") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.1 KiB
7.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Hybrid traditional + AI-first webapp built on the Crema design system. This file is a quick map, not a duplication of upstream docs.
Scripts
npm run dev— Vite dev server (React Router 7).npm run build— production build (react-router build).npm run start— serve the built app (react-router-serve ./build/server/index.js).npm run typecheck—react-router typegen && tsc. See gotcha below; may crash.start.sh/stop.sh— repo's preferred way to run/stop the dev server in the background.
There is no test runner configured. package.json has no test script and no vitest dep — verify changes by reading code and running the dev server.
App layout (app/)
routes/+routes.ts— file-based React Router 7 routes (Overview, Resources, Activity, Assistant, Library, Settings).components/layout/—app-shell.tsx(rail + appbar + avatar dropdown),appbar.tsx,theme-toggle.tsx. Template code, not a lib — fork it freely.components/assistant/message-body.tsx— markdown rendering for assistant replies + action-block pill.components/scripts-dialog.tsx— ⌘⇧P script runner UI.lib/identity.ts—useBrand()/useUser()(default stubs; swap for real session).lib/llm-settings.ts— persisted LLM endpoint + context budget config.lib/page-meta.ts,lib/utils.ts— small helpers.app.css— Tailwind v4 entrypoint; theme@importfirst, then tailwind, then per-lib@sourcelines.root.tsx—ToastProvider+CommandBusProviderwrap point.
What this is
- React Router 7 + Tailwind v4 SPA.
- Hybrid traditional + AI-first scaffold. Most surfaces are normal; the
Assistant surface is wrapped in
<AppShell theme="mightypix">for the AI-styled mood (warm cream + ink-blue + serif prose). - Built on Crema libs (
@crema/*-ui) cloned as sibling directories, not npm packages. - The
@crema/action-buslib is the foundation: anything (LLM, scripts, WebSocket, tests) can drive the UI via[data-action]-tagged elements. Seedocs/AI_FIRST.md.
Crema system (authoritative)
- Manifest (canonical catalog of all libs and themes) lives in the
crema-manifestrepo. The Gitea raw-file HTTP URL 404s, but the repo is publicly cloneable — fetch it with:Each entry hasgit clone --depth 1 https://git.sky-ai.com/CremaUIStudio/crema-manifest.git /tmp/crema-manifest && cat /tmp/crema-manifest/manifest.jsonname,alias(@crema/<name>),category,description,navLabel,navIcon, anddemo.files[]. Check this before building any UI primitive — there's a good chance alib-*-uialready does it. The per-libsrc/index.tsx// PURPOSE/// EXPORTSheader in the sibling repo is the same info at finer grain. - Each
@crema/*-uilib is its own git repo athttps://git.sky-ai.com/CremaUIStudio/lib-<name>-ui.git, cloned as a sibling of this app. Edits to lib code commit to that lib's repo, not this one. - Themes (
lib-theme-*) are CSS-only token files at the same Gitea org.
Adding a lib after scaffold
Prefer the CLI:
crema add <lib-name> # e.g. crema add status-ui chart-ui
It clones the lib as a sibling, adds the @source line to app/app.css, and wires tsconfig.json paths.
Manual fallback (3 edits):
- Clone
lib-<name>-uias a sibling. app/app.css→ add@source "../../lib-<name>-ui/src";tsconfig.jsonpaths → add"@crema/<name>-ui": ["../lib-<name>-ui/src/index.tsx"]and the/*variant.
Theme convention
- A single theme (
lib-theme-mightypixby default) is loaded via:rootinapp/app.css, first so its embedded@import url(...)Google Fonts declarations resolve to the top of the output. - Themes are self-contained: tokens and their font
@import url(...)ship inside the theme's CSS file. - Per-surface alt themes can be scoped via
[data-theme="<name>"]and applied with the shell'sthemeprop. The Assistant route already does this:<AppShell title="Assistant" theme="mightypix">…</AppShell>. - Components reference tokens (
var(--card),bg-card, etc.), never hex values. Seeapp/components/layout/THEME_CONTRACT.mdfor the full token list any theme must implement. - Assistant prose uses
var(--font-ai-prose). Don't hard-code font families.
Coding conventions
lib-*-uicomponents use inline styles with CSS variables (style={{ background: "var(--card)", color: "var(--foreground)" }}), not Tailwind classes. App routes use Tailwind freely with theme-variable utilities (bg-card,text-muted-foreground).- Every shadcn-style component has a
[data-slot="..."]attribute — themes target these for surface treatment overrides. Preserve them when editing libs. - Lib
src/index.tsxfiles start with// PURPOSE:and// EXPORTSblocks, plus"use client"at the top. Maintain the header. - Don't hardcode colors. Use tokens.
Polyrepo gotchas
git statusat this app's root only shows app changes. To see lib edits,cd ../lib-<name>-ui && git status.- Each repo commits and pushes separately.
- Don't bundle lib edits into app commits.
- Sibling libs already cloned next to this app include the full Crema set (
lib-chat-ui,lib-table-ui,lib-chart-ui,lib-theme-mightypix, etc.) — check../lib-*before adding anything new.
Marker contract (CLI-managed regions)
This repo was scaffolded from create-crema-app, which patches marker comments. Preserve them when editing:
| File | Marker |
|---|---|
tsconfig.json |
"// CREMA:PATHS" |
app/app.css |
/* CREMA:SOURCES */ |
app/routes.ts |
// CREMA:ROUTES |
app/components/layout/app-shell.tsx |
// CREMA:NAV-ICONS, // CREMA:NAV-ITEMS |
app/root.tsx |
// CREMA:PROVIDERS-IMPORTS, /* CREMA:PROVIDERS-WRAP-OPEN */, /* CREMA:PROVIDERS-WRAP-CLOSE */ |
Common tasks
- Run dev:
npm run dev - Add a UI primitive: check the manifest first; if it exists,
crema add <lib>; if not, build inline and consider whether it should become a lib. - Add a route: create the file under
app/routes/, register inapp/routes.ts, add a nav entry in the sidenav (traditional) or chat shell (AI). - Switch theme on a route: pass
theme="<name>"to<AppShell>. Default (no prop) uses the:roottheme. - Add a script: drop a
.scriptfile intopublic/scripts/, register it inKNOWN_SCRIPTSinapp/components/scripts-dialog.tsxif you want it in the dialog list, or invoke programmatically withrunScript("<name>"). - Make a component scriptable: add
data-action="<id>". The bus auto-discovers it.
Known gotchas
npm run typecheckmay crash with a TypeScript internal error — pre-existing in the Crema toolchain. There's no test runner here, so rely on careful reads + dev server.- Vite "Outdated Optimize Dep" 504s after editing
vite.config.tsortsconfig.json: stop dev,rm -rf node_modules/.vite, restart, hard-reload. - After editing a sibling lib's exports, the dev server sometimes needs a manual restart to pick up the new types.