WebClaw app lives in apps/webclaw and is built with React + TanStack Router + Tailwind CSS v4.
pnpm -C apps/webclaw dev— Start development serverpnpm -C apps/webclaw build— Build for productionpnpm -C apps/webclaw preview— Preview production buildpnpm -C apps/webclaw test— Run testspnpm -C apps/webclaw lint— Run ESLintpnpm -C apps/webclaw format— Run Prettierpnpm -C apps/webclaw check— Format and lint fix
- Functions: Always use the
functionkeyword. Avoidconstfor function definitions. - Types: Always use
type T = { ... }. Do not useinterface. - File Naming: Use
kebab-casefor all files (e.g.,chat-screen.tsx,use-session.ts). - NEVER use useEffect for anything that can be expressed as render logic
- MUST use cn utility (clsx + tailwind-merge) for class logic
- Routes live in
apps/webclaw/src/routesusing TanStack file routing. - Global styles and CSS variables live in
apps/webclaw/src/styles.css. - Local environment values go in
apps/webclaw/.env.local.
- Typography: Never use font weights bolder than
font-medium. Apply small negative tracking (tracking-tightor similar) on main titles. - Colors:
- Use the custom Tailwind palette (e.g.,
bg-primary-50,text-primary-900). - Never use arbitrary color values.
- Avoid
bg-white,bg-black,text-white,text-black, andoutline-black; use primary palette tokens instead.
- Use the custom Tailwind palette (e.g.,
- Markdown Titles: Avoid top margin on markdown headings.
- MUST use text-balance for headings and text-pretty for body/paragraphs
- MUST use tabular-nums for data
- SHOULD use truncate or line-clamp for dense UI
- NEVER modify letter-spacing (tracking-*) unless explicitly requested
- MUST use a fixed z-index scale (no arbitrary z-*)
- SHOULD use size-_ for square elements instead of w-_ + h-*
- Icons:
- All icons should use
size={20}andstrokeWidth={1.5}consistently
- All icons should use
- React 19 Refs: Use regular
functioncomponents with direct ref passing instead ofReact.forwardRef(React 19 supports refs as regular props)
- Avoid chat-wide rerenders while streaming: memoize large UI blocks and pass stable callbacks.
- Prefer passing derived data (maps/ids) instead of whole arrays when only lookups are needed.
- Keep prompt input state local to the composer when possible to avoid chat-wide rerenders on keystrokes.
- Memoize message rows with content-based equality and avoid passing freshly created objects that bust memoization.
- When scroll containers host frequently-updating content, memoize the scroll shell and portal the changing content to reduce root rerenders.
- Keep scroll position state inside scroll controls; avoid context state that forces scroll shells to rerender.
- For chat messages, write optimistic items directly into the history cache and reconcile when server history arrives (clientId/near-timestamp matching).
- For session rename/delete, optimistically update the sessions cache in mutation
onMutate, rollback on error, then invalidate on success.