| name | essentials |
| description | Critical rules that must always be followed |
Source Cursor rule: .cursor/rules/essentials.mdc.
Original file scope: **/*.{ts,tsx}.
Original Cursor alwaysApply: true.
Essentials
Package Manager
Use bun, never npm/yarn/pnpm.
bun install
bun add <pkg>
bun run <script>
bunx <cmd>
Components
Use @trycompai/design-system first, @trycompai/ui only as fallback.
import { Button, Card, Input, Select } from '@trycompai/design-system';
import { Add, Close } from '@trycompai/design-system/icons';
import { Button } from '@trycompai/ui/button';
import { Plus } from 'lucide-react';
No className on DS components - use variants and props only.
<Button variant="destructive" size="sm">Delete</Button>
<Button className="bg-red-500">Delete</Button>
TypeScript
No any. No unsafe type assertions.
const TaskSchema = z.object({ id: z.string(), title: z.string() });
const task = TaskSchema.parse(response.data);
const data: any = fetchData();
const task = response as Task;
Data Fetching
Get organizationId from URL params, not session.
export default async function Page({ params }: { params: Promise<{ orgId: string }> }) {
const { orgId } = await params;
}
const session = await auth.api.getSession();
const orgId = session?.session?.activeOrganizationId;
Server components fetch, pass to client with SWR fallbackData.
const data = await fetchData(orgId);
return <ClientComponent initialData={data} />;
const { data } = useSWR(key, fetcher, { fallbackData: initialData });
State Management
No nuqs - use React useState for UI state, Next.js for URL state.
const [isOpen, setIsOpen] = useState(false);
import { useQueryState } from 'nuqs';
After Changes
Always run checks after code changes:
bun run typecheck
bun run lint
Fix all errors before committing.