# Cursor

> Wire Cursor to respect your kit's conventions via .cursorrules.

[Cursor](https://cursor.com) auto-loads `.cursorrules` (or `.cursor/rules/*.mdc` for v0.43+)
from the project root. OTF kits ship a `.cursorrules` that mirrors `CLAUDE.md` so Cursor
chat respects the same conventions.

## .cursorrules vs .cursor/rules

Cursor supports two formats:

- **`.cursorrules`** — single file at project root. Works in all Cursor versions.
- **`.cursor/rules/*.mdc`** — directory of rule files, each scoped to specific glob patterns.
  Better for large kits where different rules apply to different paths.

The OTF kits use **`.cursorrules`** for simplicity. If your kit grows, splitting into
`.cursor/rules/` is straightforward.

## What goes in .cursorrules

Same content as `CLAUDE.md`, just rephrased to be more directive:

```md title="kits/<your-kit>/.cursorrules"
You are working inside the OTF SaaS Dashboard kit. The stack:

- Vite 6 + React 19, TanStack Router for routing, TanStack Query for data
- Hono 4 + Bun 1.3 server (same process as static SPA)
- Postgres + Drizzle ORM
- Better Auth 1.3 (email + Google + demo login)
- @otfdashkit/ui (Radix + Tailwind) for components

## Conventions you must follow

1. **Strict TypeScript.** No `any`, no `as` casts unless documented.
2. **Functional components.** `forwardRef` only on DOM-leaf components.
3. **Tailwind token classes only** — `bg-background`, `text-foreground`,
   `border-border`. Never hardcode hex.
4. **Hooks follow the optimistic-update pattern** in `src/hooks/useProjects.ts`.
5. **Hono routes follow the standard CRUD shape** in `server/routes/projects.ts`.

## When you add a screen

1. Create `src/pages/home/<name>.tsx`, wrap content in `<FadeIn>` + `<Page>`/`<PageHeader>`/`<PageBody>`
2. Add a route in `src/main.tsx` via `createRoute(...)` + add to `homeLayoutRoute.addChildren([...])`
3. Add a sidebar item in `src/components/Sidebar.tsx` (Lucide icon)
4. Optional: add a hotkey via `useEffect` keydown listener

Every page must have a loading <Skeleton>, an <EmptyState> for zero data, and a <FadeIn> mount.
```

## Tips

- **Lead with rules, not facts.** Cursor's chat model responds best to imperatives ("you must",
  "always", "never").

- **Keep examples inline.** Don't link to `docs/`; Cursor doesn't auto-fetch external files
  the way Claude Code does.

- **Pin the file in chat.** Cursor's chat respects `.cursorrules` automatically, but if you're
  doing complex multi-file work, dragging the file into chat reinforces the rules each turn.

- **Use Composer for larger refactors.** `.cursorrules` applies to Composer too, so kit
  conventions flow through.

## When .cursorrules and CLAUDE.md drift

It will happen. The fix:

1. Decide where your source of truth is. We pick `CLAUDE.md` because Claude Code is the
   primary editor for the OTF master repo.
2. Treat `.cursorrules` as a derived artifact.
3. Phase 6 ships `@otfdashkit/ai` to regenerate one from the other automatically.

Until that ships, manual sync is fine — kit conventions don't change daily.
