RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/supabase-supabase-claude-claude ↔ supabase-supabase-apps-studio-claude

Comparison

A · CLAUDE.md · supabase/supabaseB · CLAUDE.md · supabase/supabase
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections0760%
Commands11227%
Section tags32243%

What each file covers

Sections

0 shared · 7 only in A · 6 only in B
  • − Supabase Monorepo
  • − Structure
  • − Common Commands
  • − CI
  • − Conventions
  • − Skills
  • − Studio
  • + Supabase Studio
  • + Skills — load before working
  • + TanStack Start migration
  • + Orientation
  • + Code style
  • + Defaults that differ here

Commands

1 shared · 12 only in A · 2 only in B
  • − pnpm dev:docs
  • − pnpm dev:www
  • − pnpm test:studio
  • − pnpm e2e
  • − pnpm build --filter=studio
  • − pnpm lint --filter=studio
  • − pnpm typecheck
  • − pnpm format
  • − pnpm generate:types
  • − pnpm api:codegen
  • − eslint-config-supabase
  • − vitest
  • + pnpm dev
  • + pnpm --filter studio run lint:ratchet
  •   pnpm dev:studio

Section tags

3 shared · 2 only in A · 2 only in B
  • − architecture
  • − monorepo
  • + testing-strategy
  • + database
  •   test
  •   lint-format
  •   code-style

Line diff

+69 added−53 removed18 unchanged20.7% identical
supabase/supabase · .claude/CLAUDE.md
@@ −1 @@
1# Supabase Monorepo
2 
3pnpm 11 + Turborepo monorepo. Requires Node >= 22.13.
4 
5## Structure
6 
7| Directory | Purpose |
8| ------------------------ | --------------------------------------------------------------------------- |
9| `apps/studio` | Supabase Studio/Dashboard — has its own `apps/studio/CLAUDE.md` (see below) |
10| `apps/docs` | Documentation site — Next.js app router, MDX (port 3001) |
11| `apps/www` | Marketing website — Next.js, app + pages (port 3000) |
12| `apps/design-system` | Component demos — source of truth for Studio UI patterns (port 3003) |
13| `apps/ui-library` | shadcn-style registry site for Supabase UI blocks (port 3004) |
14| `apps/lite-studio` | Lightweight Studio — different stack: React Router 7 + Vite + Tailwind v4 |
15| `packages/ui` | Shared UI components (shadcn/ui based) — `import { Button } from 'ui'` |
16| `packages/ui-patterns` | Composite components — subpath imports, e.g. `ui-patterns/AssistantChat` |
17| `packages/common` | Shared utils, telemetry constants, feature flags |
18| `packages/api-types` | Generated platform Management API types |
19| `packages/pg-meta` | SQL builders for Postgres introspection (`SafeSqlFragment`) |
20| `packages/shared-data` | Static data: pricing, plans, regions, error codes |
21| `e2e/studio`, `e2e/docs` | Playwright E2E tests |
22| `supabase/` | Local Supabase project: edge functions, migrations, config.toml |
23 
24## Common Commands
 
 
 
 
 
 
 
 
 
 
 
25 
26```bash
27pnpm dev:studio # run Studio dev server → http://localhost:8082
28pnpm dev:docs # run docs dev server
29pnpm dev:www # run www dev server
30pnpm test:studio # Studio unit tests (vitest)
31pnpm e2e # Studio E2E tests (playwright)
32pnpm build --filter=studio # build Studio
33pnpm lint --filter=studio # lint Studio
34pnpm typecheck # typecheck all packages
35pnpm format # Prettier write (check: pnpm test:prettier)
36pnpm generate:types # local DB types → supabase/functions/common/database-types.ts
37pnpm api:codegen # platform Management API types → packages/api-types
38```
39 
40## CI
41 
42Every PR must pass typecheck + lint (one workflow), Prettier, and a typos check. Other checks are path-filtered: Studio unit tests/build and the lint ratchet (ESLint warning count must not increase) run on `apps/studio/**` changes; app-specific test suites run on their own paths.
 
 
 
 
43 
44Never hand-edit generated files: `packages/api-types/types/**`, `**/routeTree.gen.ts`, `**/__generated__/**`, `apps/docs/features/docs/generated/**`, `apps/www/.generated/**`, `supabase/functions/common/database-types.ts`.
45 
46## Conventions
 
 
 
 
 
 
 
47 
48**UI** — import from `'ui'`; primitives are shadcn/ui-based and exported unsuffixed (`Input`, `Select`, `Form`, …). Use `Button` — the in-house component and the standard everywhere (a raw shadcn `Button_Shadcn_` also exists but is rarely the right choice). Check `packages/ui/index.tsx` before creating new primitives. Higher-level patterns live in `packages/ui-patterns`.
49 
50**Styling** — Tailwind only, semantic tokens (`bg-muted`, `text-foreground-light`), no hardcoded colors.
51 
52**Exports** — named exports only; default exports are allowed only where a framework requires them (`pages/**`, `app/**`, config files — the eslint preset has the exact carve-out list). Lint-enforced across all apps via `eslint-config-supabase` (severity `warn` everywhere; hard-enforced in Studio by the lint ratchet).
 
 
53 
54**Language** — Use U.S. English everywhere.
 
 
 
 
 
55 
56## Skills
 
 
 
 
 
 
 
57 
58The skills in `.claude/skills/` are the source of truth for conventions — load the relevant ones before working, don't guess:
 
 
 
 
 
 
59 
60- `copywriting` — any user-facing text, anywhere in the monorepo
61- `docs-content` — anything under `apps/docs`
62- `telemetry-standards` — PostHog events, `packages/common/telemetry-constants.ts`
63- `dev-toolbar-review` — `packages/dev-tools`, `packages/common/posthog-client.ts`, `packages/common/feature-flags.tsx`
64- `safe-sql-execution` — any code that builds or executes SQL against user databases
65- `react-hook-form` — writing or modifying any form code, anywhere in the monorepo
66- `vitest` / `vercel-composition-patterns` — generic unit-testing and React composition references
67 
68## Studio
69 
70Before working on anything in `apps/studio`, read `apps/studio/CLAUDE.md` if it isn't already in context — it maps Studio tasks to required skills and covers the TanStack Start migration rules.
 
 
 
 
 
 
 
71 
supabase/supabase · apps/studio/CLAUDE.md
@@ +1 @@
1# Supabase Studio
2 
3Next.js pages router + TanStack Start (mid-migration, see below), React 19. Dev server: `pnpm dev:studio` → http://localhost:8082.
4 
5## Skills — load before working
6 
7Load the skills matching the task; stack them when a task spans areas:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8 
9| Task | Additional skills |
10| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
11| Query/mutation hooks, query keys (`data/**`) | `studio-queries` |
12| UI: pages, forms, tables, charts, sheets, empty states | `studio-ui-patterns` |
13| Form logic: react-hook-form fields, watch/formState, reset, number inputs | `react-hook-form` |
14| Displaying API errors | `studio-error-handling` |
15| Tests (deciding, writing, reviewing) | `studio-testing`, then `studio-mock-api-tests` (component/MSW) or `studio-e2e-tests` (Playwright) |
16| PostHog event tracking | `telemetry-standards` |
17| SQL against user databases | `safe-sql-execution` |
18| Logs Explorer SQL, `data/logs` | `clickhouse-logs-queries` |
19| Component API design, boolean-prop refactors | `vercel-composition-patterns` |
20| User-facing copy | `copywriting` |
21 
22## TanStack Start migration
 
 
 
 
 
 
 
 
 
 
 
 
23 
24Studio is migrating from the Next.js pages router (`pages/**`) to TanStack Start (`routes/**`). Both runtimes ship side-by-side; the `STUDIO_FRAMEWORK` env var selects which one `pnpm dev`/`build` runs (default: `next`, resolved in `scripts/dispatch.js`). Full route map and strategy: `TANSTACK_MIGRATION.md`.
25 
26- **Never delete a page file.** Most `routes/**` files are thin wrappers re-exporting the default export of their `pages/**` counterpart, so the Next file is load-bearing for both runtimes until the final cleanup pass.
27- Pure page-body edits propagate to the route automatically. Mirror a change by hand into the corresponding `routes/**` file only when it touches what the route duplicates: `getLayout`/layout wrapping, page titles or other `staticData` (incl. `skip*Layout` flags), `withAuth`, or redirect paths.
28- A new page under `pages/**` needs a matching route under `routes/**` plus a checklist entry in `TANSTACK_MIGRATION.md`.
29- New code uses native TanStack APIs — no `next/router` or `next/link`. The `compat/next/` shims exist only for legacy re-exported pages.
30- `routeTree.gen.ts` is generated by the Vite plugin — never hand-edit.
31 
32## Orientation
33 
34- **Data layer** — all platform API calls go through `data/fetchers.ts` (`openapi-fetch`, typed by the generated `api-types` package) with `handleError`; never raw `fetch`. One folder per resource in `data/`, most with a `keys.ts` query-key factory.
35- **State** — valtio for global state (`state/`), nuqs for URL state, react-hook-form + zod for forms.
36- **Platform vs self-hosted** — `IS_PLATFORM` gates platform-only behavior; `withAuth` is a no-op when self-hosted.
37- **Telemetry** — `useTrack()` from `lib/telemetry/track`; event types live in `packages/common/telemetry-constants.ts`.
38- **Tests** — default to including relevant tests with any change: a couple of unit tests for extracted logic, component tests for UI behavior, E2E only when the scope demands it (`studio-testing` has the decision tree). Not every PR needs them, but "no tests" should be a considered choice, not the default. Tooling: vitest + MSW; component tests use `customRender` + `addAPIMock` from `tests/lib/`; unhandled network requests fail tests. Don't `vi.mock('@/data/...')`.
39- **Shortcuts** — use the registry in `state/shortcuts/` and `components/ui/Shortcut*.tsx`; keep `G then …` chords for navigation; no one-off keyboard listeners.
40- **Reuse first** — before writing a new hook or helper, search for an existing one (`hooks/`, `lib/`, `packages/common`, `packages/ui-patterns`). If you do need a new one, make it as reusable as possible: general naming, no page-specific coupling, placed where other callers can find it.
41- Co-locate sub-components with their parent; avoid barrel re-export files.
42 
43## Code style
44 
45Older Studio code predates some of these conventions. For new or modified code, follow them rather than mirroring nearby legacy patterns:
46 
47- **Booleans** read as `is`/`has`/`can`/`should`. Derive them from existing state (`const isFormValid = name.length > 0 && email.includes('@')`) — mirroring a derivable value into `useState` synced by `useEffect` is a bug pattern. Give multi-condition logic a name (`const canShowAddButton = !isSchemaLocked && canUpdateColumns && …`) instead of inlining the chain in JSX.
48- **Ternaries**: one is fine for a binary choice; never nest them. Anything bigger flattens — early returns in statement position, sibling `&&` blocks in JSX.
49- **Fetch states** render with early returns at the top level, or a flat `&&` chain with mutually exclusive guards inline — never a nested ternary:
50 
51 ```tsx
52 // Top level: early return per state
53 if (isLoading) return <GenericSkeletonLoader />
54 if (isError) return <AlertError error={error} subject="Failed to retrieve data" />
55 if (isSuccess && data.length === 0) return <EmptyState />
56 return <DataDisplay data={data} />
57 
58 // Inline: flat `&&` blocks, mutually exclusive guards
59 <div>
60 {isLoading && <ShimmeringLoader />}
61 {isError && <AlertError error={error} />}
62 {isSuccess && data.length === 0 && <EmptyState />}
63 {isSuccess && data.length > 0 && <DataDisplay data={data} />}
64 </div>
65 ```
66 
67- **`useEffect` is for synchronizing with external systems** (subscriptions, DOM, timers) — not for deriving data (compute it in render), reacting to user actions (do it in the handler), or fetching (React Query). Older code uses effects for all of these; don't copy it.
68- **State** stays as local as possible — lift it only when it's actually shared. Related form fields belong in a single react-hook-form + zod form, not parallel `useState` calls.
69- **Component size**: split at ~200–300 lines — or sooner when a component grows multiple distinct UI sections, tangled conditional rendering, or clusters of unrelated `useState`. Extract repeated JSX into small components, non-trivial pure logic into `.utils.ts` functions (which get unit tests), and reusable stateful logic into custom hooks.
70- **Memoization is not the default**: `useMemo`/`useCallback` only for measured expense or referential stability a memoized child depends on.
71- **TypeScript**: avoid `as` casts — where external data enters, parse it with zod (`schema.parse`/`safeParse`) instead. Model multi-state values as discriminated unions (`{ status: 'success'; data: T } | { status: 'error'; error: Error }`) rather than independent boolean flags.
72- **Naming**: prop callbacks are `onX`, internal handlers are `handleX`. Custom hooks return objects, not tuples.
73- **Refactoring**: when you move or extract code into a new module, update every importer to point at the new location directly — do **not** leave a re-export shim in the old file "for backward compatibility." It's a one-line import change per consumer, and keeping shims around makes the codebase messy and the true source of a symbol ambiguous.
74 
75## Defaults that differ here
 
 
 
 
 
 
76 
77- **ESLint warnings are ratcheted in CI**: the per-rule occurrence count must not increase, so a new `any`, unresolved `exhaustive-deps` warning, or default export fails the build even though it's "only a warning". Check locally with `pnpm --filter studio run lint:ratchet`.
78- **Clipboard**: `copyToClipboard` from `'ui'`, and never `await` anything before calling it (Safari requires the write inside the user gesture; lint-enforced) — pass a Promise as the argument instead.
79- **`useParams()` comes from `'common'`**, not `next/navigation` — it camelCases keys and returns `string | undefined`.
80- **Permissions**: `useAsyncCheckPermissions` from `hooks/misc/useCheckPermissions` (returns `can: true` when self-hosted).
81- **Gating**: `useIsFeatureEnabled` for product features, `useFlag` from `'common'` for feature flags — two different systems.
82- **Dates**: `dayjs` (plugins pre-loaded at both entries, `pages/_app.tsx` and `routes/__root.tsx`), not `date-fns`. **Toasts**: `toast` from `'sonner'`.
83- **Import split**: `'ui'` = primitives, `'ui-patterns'` = composed patterns (`ConfirmationModal`, …), `@ui/*` = alias into `packages/ui/src`. Icons come from `lucide-react`.
84- **New tables** use `@tanstack/react-table`; `react-data-grid` is banned for new code.
85- **Ad-hoc SQL** against the user's database goes through `executeSql` / `useExecuteSqlMutation` (`data/sql/execute-sql-mutation`).
86- **Confirmations**: `ConfirmationModal` / `TextConfirmModal` from `ui-patterns`, never `window.confirm`. Disabled buttons needing an explanation use `ButtonTooltip`; inline warnings use `Admonition`.
87 
@@ −1 +1 @@
1−# Supabase Monorepo
1+# Supabase Studio
22  
3−pnpm 11 + Turborepo monorepo. Requires Node >= 22.13.
3+Next.js pages router + TanStack Start (mid-migration, see below), React 19. Dev server: `pnpm dev:studio` → http://localhost:8082.
44  
5−## Structure
5+## Skills — load before working
66  
7−| Directory | Purpose |
8−| ------------------------ | --------------------------------------------------------------------------- |
9−| `apps/studio` | Supabase Studio/Dashboard — has its own `apps/studio/CLAUDE.md` (see below) |
10−| `apps/docs` | Documentation site — Next.js app router, MDX (port 3001) |
11−| `apps/www` | Marketing website — Next.js, app + pages (port 3000) |
12−| `apps/design-system` | Component demos — source of truth for Studio UI patterns (port 3003) |
13−| `apps/ui-library` | shadcn-style registry site for Supabase UI blocks (port 3004) |
14−| `apps/lite-studio` | Lightweight Studio — different stack: React Router 7 + Vite + Tailwind v4 |
15−| `packages/ui` | Shared UI components (shadcn/ui based) — `import { Button } from 'ui'` |
16−| `packages/ui-patterns` | Composite components — subpath imports, e.g. `ui-patterns/AssistantChat` |
17−| `packages/common` | Shared utils, telemetry constants, feature flags |
18−| `packages/api-types` | Generated platform Management API types |
19−| `packages/pg-meta` | SQL builders for Postgres introspection (`SafeSqlFragment`) |
20−| `packages/shared-data` | Static data: pricing, plans, regions, error codes |
21−| `e2e/studio`, `e2e/docs` | Playwright E2E tests |
22−| `supabase/` | Local Supabase project: edge functions, migrations, config.toml |
7+Load the skills matching the task; stack them when a task spans areas:
238  
24−## Common Commands
9+| Task | Additional skills |
10+| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
11+| Query/mutation hooks, query keys (`data/**`) | `studio-queries` |
12+| UI: pages, forms, tables, charts, sheets, empty states | `studio-ui-patterns` |
13+| Form logic: react-hook-form fields, watch/formState, reset, number inputs | `react-hook-form` |
14+| Displaying API errors | `studio-error-handling` |
15+| Tests (deciding, writing, reviewing) | `studio-testing`, then `studio-mock-api-tests` (component/MSW) or `studio-e2e-tests` (Playwright) |
16+| PostHog event tracking | `telemetry-standards` |
17+| SQL against user databases | `safe-sql-execution` |
18+| Logs Explorer SQL, `data/logs` | `clickhouse-logs-queries` |
19+| Component API design, boolean-prop refactors | `vercel-composition-patterns` |
20+| User-facing copy | `copywriting` |
2521  
26−```bash
27−pnpm dev:studio # run Studio dev server → http://localhost:8082
28−pnpm dev:docs # run docs dev server
29−pnpm dev:www # run www dev server
30−pnpm test:studio # Studio unit tests (vitest)
31−pnpm e2e # Studio E2E tests (playwright)
32−pnpm build --filter=studio # build Studio
33−pnpm lint --filter=studio # lint Studio
34−pnpm typecheck # typecheck all packages
35−pnpm format # Prettier write (check: pnpm test:prettier)
36−pnpm generate:types # local DB types → supabase/functions/common/database-types.ts
37−pnpm api:codegen # platform Management API types → packages/api-types
38−```
22+## TanStack Start migration
3923  
40−## CI
24+Studio is migrating from the Next.js pages router (`pages/**`) to TanStack Start (`routes/**`). Both runtimes ship side-by-side; the `STUDIO_FRAMEWORK` env var selects which one `pnpm dev`/`build` runs (default: `next`, resolved in `scripts/dispatch.js`). Full route map and strategy: `TANSTACK_MIGRATION.md`.
4125  
42−Every PR must pass typecheck + lint (one workflow), Prettier, and a typos check. Other checks are path-filtered: Studio unit tests/build and the lint ratchet (ESLint warning count must not increase) run on `apps/studio/**` changes; app-specific test suites run on their own paths.
26+- **Never delete a page file.** Most `routes/**` files are thin wrappers re-exporting the default export of their `pages/**` counterpart, so the Next file is load-bearing for both runtimes until the final cleanup pass.
27+- Pure page-body edits propagate to the route automatically. Mirror a change by hand into the corresponding `routes/**` file only when it touches what the route duplicates: `getLayout`/layout wrapping, page titles or other `staticData` (incl. `skip*Layout` flags), `withAuth`, or redirect paths.
28+- A new page under `pages/**` needs a matching route under `routes/**` plus a checklist entry in `TANSTACK_MIGRATION.md`.
29+- New code uses native TanStack APIs — no `next/router` or `next/link`. The `compat/next/` shims exist only for legacy re-exported pages.
30+- `routeTree.gen.ts` is generated by the Vite plugin — never hand-edit.
4331  
44−Never hand-edit generated files: `packages/api-types/types/**`, `**/routeTree.gen.ts`, `**/__generated__/**`, `apps/docs/features/docs/generated/**`, `apps/www/.generated/**`, `supabase/functions/common/database-types.ts`.
32+## Orientation
4533  
46−## Conventions
34+- **Data layer** — all platform API calls go through `data/fetchers.ts` (`openapi-fetch`, typed by the generated `api-types` package) with `handleError`; never raw `fetch`. One folder per resource in `data/`, most with a `keys.ts` query-key factory.
35+- **State** — valtio for global state (`state/`), nuqs for URL state, react-hook-form + zod for forms.
36+- **Platform vs self-hosted** — `IS_PLATFORM` gates platform-only behavior; `withAuth` is a no-op when self-hosted.
37+- **Telemetry** — `useTrack()` from `lib/telemetry/track`; event types live in `packages/common/telemetry-constants.ts`.
38+- **Tests** — default to including relevant tests with any change: a couple of unit tests for extracted logic, component tests for UI behavior, E2E only when the scope demands it (`studio-testing` has the decision tree). Not every PR needs them, but "no tests" should be a considered choice, not the default. Tooling: vitest + MSW; component tests use `customRender` + `addAPIMock` from `tests/lib/`; unhandled network requests fail tests. Don't `vi.mock('@/data/...')`.
39+- **Shortcuts** — use the registry in `state/shortcuts/` and `components/ui/Shortcut*.tsx`; keep `G then …` chords for navigation; no one-off keyboard listeners.
40+- **Reuse first** — before writing a new hook or helper, search for an existing one (`hooks/`, `lib/`, `packages/common`, `packages/ui-patterns`). If you do need a new one, make it as reusable as possible: general naming, no page-specific coupling, placed where other callers can find it.
41+- Co-locate sub-components with their parent; avoid barrel re-export files.
4742  
48−**UI** — import from `'ui'`; primitives are shadcn/ui-based and exported unsuffixed (`Input`, `Select`, `Form`, …). Use `Button` — the in-house component and the standard everywhere (a raw shadcn `Button_Shadcn_` also exists but is rarely the right choice). Check `packages/ui/index.tsx` before creating new primitives. Higher-level patterns live in `packages/ui-patterns`.
43+## Code style
4944  
50−**Styling** — Tailwind only, semantic tokens (`bg-muted`, `text-foreground-light`), no hardcoded colors.
45+Older Studio code predates some of these conventions. For new or modified code, follow them rather than mirroring nearby legacy patterns:
5146  
52−**Exports** — named exports only; default exports are allowed only where a framework requires them (`pages/**`, `app/**`, config files — the eslint preset has the exact carve-out list). Lint-enforced across all apps via `eslint-config-supabase` (severity `warn` everywhere; hard-enforced in Studio by the lint ratchet).
47+- **Booleans** read as `is`/`has`/`can`/`should`. Derive them from existing state (`const isFormValid = name.length > 0 && email.includes('@')`) — mirroring a derivable value into `useState` synced by `useEffect` is a bug pattern. Give multi-condition logic a name (`const canShowAddButton = !isSchemaLocked && canUpdateColumns && …`) instead of inlining the chain in JSX.
48+- **Ternaries**: one is fine for a binary choice; never nest them. Anything bigger flattens — early returns in statement position, sibling `&&` blocks in JSX.
49+- **Fetch states** render with early returns at the top level, or a flat `&&` chain with mutually exclusive guards inline — never a nested ternary:
5350  
54−**Language** — Use U.S. English everywhere.
51+ ```tsx
52+ // Top level: early return per state
53+ if (isLoading) return <GenericSkeletonLoader />
54+ if (isError) return <AlertError error={error} subject="Failed to retrieve data" />
55+ if (isSuccess && data.length === 0) return <EmptyState />
56+ return <DataDisplay data={data} />
5557  
56−## Skills
58+ // Inline: flat `&&` blocks, mutually exclusive guards
59+ <div>
60+ {isLoading && <ShimmeringLoader />}
61+ {isError && <AlertError error={error} />}
62+ {isSuccess && data.length === 0 && <EmptyState />}
63+ {isSuccess && data.length > 0 && <DataDisplay data={data} />}
64+ </div>
65+ ```
5766  
58−The skills in `.claude/skills/` are the source of truth for conventions — load the relevant ones before working, don't guess:
67+- **`useEffect` is for synchronizing with external systems** (subscriptions, DOM, timers) — not for deriving data (compute it in render), reacting to user actions (do it in the handler), or fetching (React Query). Older code uses effects for all of these; don't copy it.
68+- **State** stays as local as possible — lift it only when it's actually shared. Related form fields belong in a single react-hook-form + zod form, not parallel `useState` calls.
69+- **Component size**: split at ~200–300 lines — or sooner when a component grows multiple distinct UI sections, tangled conditional rendering, or clusters of unrelated `useState`. Extract repeated JSX into small components, non-trivial pure logic into `.utils.ts` functions (which get unit tests), and reusable stateful logic into custom hooks.
70+- **Memoization is not the default**: `useMemo`/`useCallback` only for measured expense or referential stability a memoized child depends on.
71+- **TypeScript**: avoid `as` casts — where external data enters, parse it with zod (`schema.parse`/`safeParse`) instead. Model multi-state values as discriminated unions (`{ status: 'success'; data: T } | { status: 'error'; error: Error }`) rather than independent boolean flags.
72+- **Naming**: prop callbacks are `onX`, internal handlers are `handleX`. Custom hooks return objects, not tuples.
73+- **Refactoring**: when you move or extract code into a new module, update every importer to point at the new location directly — do **not** leave a re-export shim in the old file "for backward compatibility." It's a one-line import change per consumer, and keeping shims around makes the codebase messy and the true source of a symbol ambiguous.
5974  
60−- `copywriting` — any user-facing text, anywhere in the monorepo
61−- `docs-content` — anything under `apps/docs`
62−- `telemetry-standards` — PostHog events, `packages/common/telemetry-constants.ts`
63−- `dev-toolbar-review` — `packages/dev-tools`, `packages/common/posthog-client.ts`, `packages/common/feature-flags.tsx`
64−- `safe-sql-execution` — any code that builds or executes SQL against user databases
65−- `react-hook-form` — writing or modifying any form code, anywhere in the monorepo
66−- `vitest` / `vercel-composition-patterns` — generic unit-testing and React composition references
75+## Defaults that differ here
6776  
68−## Studio
69− 
70−Before working on anything in `apps/studio`, read `apps/studio/CLAUDE.md` if it isn't already in context — it maps Studio tasks to required skills and covers the TanStack Start migration rules.
77+- **ESLint warnings are ratcheted in CI**: the per-rule occurrence count must not increase, so a new `any`, unresolved `exhaustive-deps` warning, or default export fails the build even though it's "only a warning". Check locally with `pnpm --filter studio run lint:ratchet`.
78+- **Clipboard**: `copyToClipboard` from `'ui'`, and never `await` anything before calling it (Safari requires the write inside the user gesture; lint-enforced) — pass a Promise as the argument instead.
79+- **`useParams()` comes from `'common'`**, not `next/navigation` — it camelCases keys and returns `string | undefined`.
80+- **Permissions**: `useAsyncCheckPermissions` from `hooks/misc/useCheckPermissions` (returns `can: true` when self-hosted).
81+- **Gating**: `useIsFeatureEnabled` for product features, `useFlag` from `'common'` for feature flags — two different systems.
82+- **Dates**: `dayjs` (plugins pre-loaded at both entries, `pages/_app.tsx` and `routes/__root.tsx`), not `date-fns`. **Toasts**: `toast` from `'sonner'`.
83+- **Import split**: `'ui'` = primitives, `'ui-patterns'` = composed patterns (`ConfirmationModal`, …), `@ui/*` = alias into `packages/ui/src`. Icons come from `lucide-react`.
84+- **New tables** use `@tanstack/react-table`; `react-data-grid` is banned for new code.
85+- **Ad-hoc SQL** against the user's database goes through `executeSql` / `useExecuteSqlMutation` (`data/sql/execute-sql-mutation`).
86+- **Confirmations**: `ConfirmationModal` / `TextConfirmModal` from `ui-patterns`, never `window.confirm`. Disabled buttons needing an explanation use `ButtonTooltip`; inline warnings use `Admonition`.
7187  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack