mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Makes the repo's AI-agent setup tool-agnostic: instructions live in
`AGENTS.md` files, skills live in `.agents/skills/`, and Claude Code,
Codex, Cursor, and Copilot all read the same sources. Also sweeps the
skills for stale and duplicated content while everything was being
moved.
**Changed:**
- Every `CLAUDE.md` (root, `apps/studio`, `apps/docs`, `apps/kb`) is now
a one-line `@AGENTS.md` import; the content moved verbatim into an
`AGENTS.md` beside it. The root one moved from `.claude/CLAUDE.md` to
the repo root for consistency.
- All skills now live in `.agents/skills/`; `.claude/skills` is a single
symlink to it (replacing the old mix of real dirs and per-skill
symlinks). Path references in `.coderabbit.yaml`, code comments, and
docs updated to match.
- `.github/copilot-instructions.md` keeps only the review policy and
points at `AGENTS.md` + `.agents/skills/`. Copilot code review reads
those natively now, so the per-topic
`.github/instructions/*.instructions.md` files were duplicates of the
skills.
- Stale skill content fixed: `studio-queries` imported a toast library
Studio doesn't use, `telemetry-standards` and `studio-testing` used
import paths that don't resolve, `safe-sql-execution` cited a boundary
test that doesn't exist, the ask-the-docs references described an
`AiPrompt` mechanism that was replaced by the ID-keyed registry, plus a
handful of wrong paths, a self-contradicting `waitForTimeout` rule, an
invalid Playwright signature, and a ConfigCat flag described as PostHog.
- `studio-error-handling` now explains when to use `AlertError` (the
default) vs `ErrorMatcher`.
**Added:**
- `apps/docs/AGENTS.md` (docs test requirements, from the old Cursor
rule)
- `studio-shortcuts` skill (from the old Copilot instruction file,
verified against the current registry)
- `ask-the-docs/reference/graphql-endpoint.md` and
`search-embeddings.md` (from the old Cursor rules, with the missing
resolver/registration/codegen steps filled in)
- Feature-flag measurement section in `telemetry-standards`
**Removed:**
- `.cursor/` (rules folded in as above; skill symlinks no longer needed)
and `.cursorignore`
- `.github/instructions/` (8 files)
- `vercel-composition-patterns/AGENTS.md` – a 946-line verbatim
concatenation of its own `rules/` directory, and a nested `AGENTS.md`
that agents could auto-load as repo instructions
- `edit-the-docs/reference/structure-and-flow.md` – word-for-word copy
of the skill's own Phase 2 text
## To test
- `readlink .claude/skills` → `../.agents/skills`, and `ls
.claude/skills/copywriting/SKILL.md` resolves
- Open a Claude Code session at the repo root and in `apps/studio` – the
imported `AGENTS.md` content should load as before
- `git diff master --stat -M` shows the skill moves as 100% renames
(content unchanged except the listed fixes)
- Spot-check a fixed claim, e.g. `import { toast } from 'sonner'` in
`studio-queries`, or the `logs.all` ESLint rule cited in
`clickhouse-logs-queries/references/codebase-integration.md`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Documentation**
- Expanded guidance for documentation workflows, GraphQL resources,
search, ClickHouse logs, React forms, Studio testing, shortcuts,
telemetry, accessibility, copywriting, and composition patterns.
- Clarified local testing, linting, build workflows, error handling, and
AI coding agent usage.
- Added contributor guidance for the knowledge base, documentation, and
Studio areas.
- **Chores**
- Consolidated agent instructions and skill references.
- Removed obsolete editor-specific guidance, duplicate links, and
superseded documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
125 lines
5.4 KiB
JavaScript
125 lines
5.4 KiB
JavaScript
const { defineConfig } = require('eslint/config')
|
|
const { fixupPluginRules } = require('@eslint/compat')
|
|
const barrelFiles = require('eslint-plugin-barrel-files')
|
|
const valtio = require('eslint-plugin-valtio')
|
|
// eslint-plugin-react-hook-form@0.3.1 (latest) still calls the ESLint 8
|
|
// `context.getScope()`, which ESLint 9 removed. fixupPluginRules shims the
|
|
// deprecated context methods so the rules run under flat config.
|
|
const reactHookForm = require('eslint-plugin-react-hook-form')
|
|
const supabaseConfig = require('eslint-config-supabase/next')
|
|
|
|
// Analytics SQL wire boundary — see the block below for context. Shared so the
|
|
// API/route block can re-include it (flat config replaces, not merges, a rule's
|
|
// options when blocks overlap, so the later block must carry these forward).
|
|
const ANALYTICS_SQL_RESTRICTED_SYNTAX = [
|
|
{
|
|
selector:
|
|
"CallExpression[callee.name=/^(post|get)$/][arguments.0.value='/platform/projects/{ref}/analytics/endpoints/logs.all']",
|
|
message:
|
|
'Do not call the analytics logs.all endpoint directly. Route through executeAnalyticsSql in @/data/logs/execute-analytics-sql so the SafeLogSqlFragment brand is enforced at compile time.',
|
|
},
|
|
{
|
|
selector:
|
|
"CallExpression[callee.name=/^(post|get)$/][arguments.0.value='/platform/projects/{ref}/analytics/endpoints/logs.all.otel']",
|
|
message:
|
|
'Do not call the analytics logs.all.otel endpoint directly. Route through executeAnalyticsSql in @/data/logs/execute-analytics-sql so the SafeLogSqlFragment brand is enforced at compile time.',
|
|
},
|
|
]
|
|
|
|
// Ban constructing a Supabase client at module scope in API route files. The
|
|
// TanStack server imports the entire route tree at boot (loadEntries), so a
|
|
// module-scope createClient with an env var that's unset in that environment
|
|
// (e.g. SUPABASE_URL on platform) throws on import and 500s every route — a
|
|
// runtime-only failure that's painful to catch. Construct it lazily inside the
|
|
// handler instead (see lib/api/self-hosted-admin.ts).
|
|
const NO_MODULE_SCOPE_CREATE_CLIENT = {
|
|
selector:
|
|
":matches(Program, ExportNamedDeclaration) > VariableDeclaration > VariableDeclarator > CallExpression[callee.name='createClient']",
|
|
message:
|
|
'Do not construct a Supabase client at module scope in API route files — the TanStack server evaluates every route module at boot, so a missing env var (e.g. SUPABASE_URL on platform) crashes every route. Construct it lazily inside the handler (see lib/api/self-hosted-admin.ts).',
|
|
}
|
|
|
|
module.exports = defineConfig([
|
|
{ files: ['**/*.ts', '**/*.tsx'] },
|
|
supabaseConfig,
|
|
{
|
|
files: ['**/*.{js,jsx,mjs,ts,tsx,mts,cts}'],
|
|
plugins: {
|
|
'barrel-files': barrelFiles,
|
|
valtio,
|
|
'react-hook-form': fixupPluginRules(reactHookForm),
|
|
},
|
|
rules: {
|
|
'@next/next/no-img-element': 'off',
|
|
'react/no-unescaped-entities': 'off',
|
|
'react/display-name': 'warn',
|
|
'react/no-unstable-nested-components': 'warn',
|
|
'react/jsx-key': 'error',
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
paths: [
|
|
{
|
|
name: 'components/ui/DataTable/DataTableColumn/DataTableColumnHeader',
|
|
message: 'Use TanStackTableHeadSort from ui-patterns/Table instead.',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
'barrel-files/avoid-re-export-all': 'error',
|
|
'jsx-a11y/alt-text': 'warn',
|
|
'jsx-a11y/role-has-required-aria-props': 'error',
|
|
'jsx-a11y/aria-props': 'warn',
|
|
'jsx-a11y/aria-proptypes': 'warn',
|
|
'jsx-a11y/role-supports-aria-props': 'warn',
|
|
'jsx-a11y/anchor-has-content': 'warn',
|
|
'jsx-a11y/control-has-associated-label': [
|
|
'warn',
|
|
{ controlComponents: ['Button', 'Switch'] },
|
|
],
|
|
'jsx-a11y/label-has-associated-control': [
|
|
'warn',
|
|
{ labelComponents: ['Label'], controlComponents: ['Input', 'Switch'] },
|
|
],
|
|
'jsx-a11y/aria-role': 'warn',
|
|
'jsx-a11y/no-redundant-roles': 'warn',
|
|
'jsx-a11y/no-aria-hidden-on-focusable': 'warn',
|
|
'jsx-a11y/tabindex-no-positive': 'warn',
|
|
'jsx-a11y/anchor-is-valid': 'warn',
|
|
'jsx-a11y/heading-has-content': 'warn',
|
|
'jsx-a11y/no-distracting-elements': 'warn',
|
|
'valtio/state-snapshot-rule': 'warn',
|
|
'valtio/avoid-this-in-proxy': 'error',
|
|
'react-hook-form/destructuring-formstate': 'error',
|
|
'react-hook-form/no-access-control': 'error',
|
|
'react-hook-form/no-nested-object-setvalue': 'error',
|
|
'react-hook-form/no-use-watch': 'warn',
|
|
},
|
|
},
|
|
// Analytics SQL wire boundary: every call to a SQL-bearing analytics
|
|
// endpoint (`logs.all` / `logs.all.otel`) must go through
|
|
// `executeAnalyticsSql` so the `SafeLogSqlFragment` brand is enforced at the
|
|
// type level. See .agents/skills/safe-sql-execution/SKILL.md.
|
|
{
|
|
files: ['**/*.ts', '**/*.tsx'],
|
|
ignores: ['data/logs/execute-analytics-sql.ts'],
|
|
rules: {
|
|
'no-restricted-syntax': ['error', ...ANALYTICS_SQL_RESTRICTED_SYNTAX],
|
|
},
|
|
},
|
|
// API route modules are eagerly imported by the TanStack server at boot, so
|
|
// module-scope side effects there are especially dangerous. This block also
|
|
// re-includes the analytics selectors because flat config replaces (not
|
|
// merges) a rule's options for overlapping files.
|
|
{
|
|
files: ['pages/api/**/*.ts', 'pages/api/**/*.tsx', 'routes/**/*.ts', 'routes/**/*.tsx'],
|
|
rules: {
|
|
'no-restricted-syntax': [
|
|
'error',
|
|
...ANALYTICS_SQL_RESTRICTED_SYNTAX,
|
|
NO_MODULE_SCOPE_CREATE_CLIENT,
|
|
],
|
|
},
|
|
},
|
|
])
|