Source profileQuality 96/100

kensaurus/cursor-kenji/skills/audit-db-schema/SKILL.md

audit-db-schema

Audit database schema for consistency, validation, and industry standards. Use when reviewing schema design, naming conventions, constraints, indexes, or migrations. Destructive-op gates → plan-data-integrity. Who-can-read-what RLS → plan-rls-audit. Restore/RPO → plan-backup-dr.

Source repository stars
9
Declared platforms
0
Static risk flags
1
Last source update
2026-08-21
Source checked
2026-08-25

Decision brief

What it does: where it fits

Degree of freedom: MIXED — Steps 0, 1, 3 [HIGH freedom]; Steps 2 and 4 MCP/SQL probes [LOW freedom — run exactly] (run the query; do not invent a schema).

Best for

  • Use when reviewing schema design, naming conventions, constraints, indexes, or migrations.

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/audit-db-schema"
Safe inspection promptEditorial

Inspect the Agent Skill "audit-db-schema" from https://github.com/kensaurus/cursor-kenji/blob/28a0bd8403c950f58ed063d47a858ee3493b0038/skills/audit-db-schema/SKILL.md at commit 28a0bd8403c950f58ed063d47a858ee3493b0038. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    How to reason

    1. Observe — quote the column, constraint, advisor row, or query result 2. Interpret — what fails at write-time, read-time, or migrate-time? 3. Classify — naming / type / constraint / index / RLS / migration / correct 4. Severity — missing FK/RLS on public data = P0; type/index…

    Observe — quote the column, constraint, advisor row, or query resultInterpret — what fails at write-time, read-time, or migrate-time?Classify — naming / type / constraint / index / RLS / migration / correct
  2. 02

    Step 0: Auto-Detect Database Environment

    Match the project by name or URL from .env, .env.local, or supabase/config.toml. Record the PROJECTID for all subsequent MCP calls.

    Match the project by name or URL from .env, .env.local, or supabase/config.toml. Record the PROJECTID for all subsequent MCP calls.
  3. 03

    Step 1: Research Schema Best Practices

    If using Drizzle, resolve drizzle-orm instead.

    If using Drizzle, resolve drizzle-orm instead.Additional searches based on detected stack:Scrape the most authoritative result:
  4. 04

    Step 2: Gather Full Schema

    Include remediation URLs from advisor results in the final report as clickable links.

    Include remediation URLs from advisor results in the final report as clickable links.
  5. 05

    Step 3: Audit Categories

    Review the “Step 3: Audit Categories” section in the pinned source before continuing.

    Review and apply the “Step 3: Audit Categories” source section.

Permission review

Static risk signals and limitations

Network access

medium · line 23

The documentation includes network, browsing, or remote request actions.

**Evidenced** — query result or advisor URL, not "Postgres usually…"

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score96/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars9SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
kensaurus/cursor-kenji
Skill path
skills/audit-db-schema/SKILL.md
Commit
28a0bd8403c950f58ed063d47a858ee3493b0038
License
MIT
Collected
2026-08-25
Default branch
main
View the original SKILL.md

Database Schema Audit Skill

Degree of freedom: MIXED — Steps 0, 1, 3 [HIGH freedom]; Steps 2 and 4 MCP/SQL probes [LOW freedom — run exactly] (run the query; do not invent a schema).

How to reason

  1. Observe — quote the column, constraint, advisor row, or query result
  2. Interpret — what fails at write-time, read-time, or migrate-time?
  3. Classify — naming / type / constraint / index / RLS / migration / correct
  4. Severity — missing FK/RLS on public data = P0; type/index drift = P1; naming = P2

Worked example

Observe: orders.user_id is nullable text, no FK, no index; rowsecurity = false. Interpret: orphan rows can insert; the client can SELECT every order; lookups seq-scan. Classify: constraint + index + RLS (not a naming nit). Severity: P0 — public table, no RLS, no FK. Finding: orders | RLS+FK | P0 | enable RLS + user_id uuid references users(id) + index.

Self-critique before reporting [LOW freedom — do not skip]

  1. Evidenced — query result or advisor URL, not "Postgres usually…"
  2. Reproducible — same SQL twice; do not cite a stale list_tables
  3. Severity justified — P0 = data loss, leak, or unconstrained money type
  4. Right owner — who-can-read-what → plan-rls-audit; DELETE/TRUNCATE → plan-data-integrity; RPO → plan-backup-dr
  5. No migrations applied — findings only

Step 0: Auto-Detect Database Environment

0a. Detect Database and ORM

SignalTechnology
@supabase/supabase-js in package.jsonSupabase (Postgres)
prisma in devDependencies, prisma/schema.prismaPrisma ORM
drizzle-orm in dependencies, drizzle/ directoryDrizzle ORM
sequelize in dependenciesSequelize ORM
sqlalchemy in requirementsSQLAlchemy (Python)
supabase/migrations/*.sql directorySupabase migrations
prisma/migrations/ directoryPrisma migrations
drizzle/migrations/ or drizzle/*.sqlDrizzle migrations

0b. Find Supabase Project ID

supabase:list_projects
{}

Match the project by name or URL from .env, .env.local, or supabase/config.toml. Record the PROJECT_ID for all subsequent MCP calls.

0c. Detect Schema Source Files

Glob: **/supabase/migrations/*.sql → Supabase SQL migrations
Glob: **/prisma/schema.prisma → Prisma schema
Glob: **/drizzle/schema.ts → Drizzle schema
Glob: **/src/db/schema.ts → Drizzle alt location
Glob: **/knexfile.* → Knex migrations
Glob: **/alembic/versions/*.py → SQLAlchemy migrations

0d. Record Discovery

DATABASE ENVIRONMENT:
- Database: [Supabase Postgres / raw Postgres / MySQL / SQLite]
- ORM: [Prisma / Drizzle / Sequelize / none]
- Project ID: [Supabase project ID or N/A]
- Migration tool: [Supabase CLI / Prisma Migrate / Drizzle Kit / Knex]
- Schema files: [list paths]
- Migration count: [N]

Step 1: Research Schema Best Practices

1a. Context7 — ORM Documentation

If using Prisma:

context7:resolve-library-id
{
 "libraryName": "prisma",
 "query": "schema best practices indexes relations"
}
context7:query-docs
{
 "libraryId": "<RESOLVED_ID>",
 "query": "schema best practices naming conventions indexes onDelete"
}

If using Drizzle, resolve drizzle-orm instead.

1b. Firecrawl — Current Database Patterns

firecrawl:firecrawl_search
{
 "query": "PostgreSQL schema design best practices [current year]",
 "limit": 5,
 "sources": [{ "type": "web" }]
}

Additional searches based on detected stack:

StackSearch Query
SupabaseSupabase RLS policies best practices performance [current year]
PrismaPrisma schema design relations indexes best practices [current year]
DrizzleDrizzle ORM schema patterns migrations [current year]
GeneralPostgreSQL indexing strategy production optimization

Scrape the most authoritative result:

firecrawl:firecrawl_scrape
{
 "url": "<BEST_RESULT_URL>",
 "formats": ["markdown"],
 "onlyMainContent": true
}

1c. Supabase Docs Search

If Supabase:

supabase:search_docs
{
 "query": "RLS policy performance best practices"
}

Step 2: Gather Full Schema

2a. List All Tables (Supabase MCP)

supabase:list_tables
{
 "project_id": "<PROJECT_ID>",
 "schemas": ["public"],
 "verbose": true
}

2b. Run Detailed Audit Queries

supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "SELECT table_name, column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_schema = 'public' ORDER BY table_name, ordinal_position"
}
supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "SELECT tc.table_name, tc.constraint_name, tc.constraint_type, kcu.column_name, ccu.table_name AS foreign_table FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name LEFT JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name WHERE tc.table_schema = 'public'"
}

2c. Gather Indexes

supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "SELECT tablename, indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' ORDER BY tablename"
}

2d. Gather RLS Status and Policies

supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename"
}
supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "SELECT schemaname, tablename, policyname, permissive, roles, cmd, qual, with_check FROM pg_policies WHERE schemaname = 'public' ORDER BY tablename"
}

2e. Run Supabase Advisors

supabase:get_advisors
{
 "project_id": "<PROJECT_ID>",
 "type": "security"
}
supabase:get_advisors
{
 "project_id": "<PROJECT_ID>",
 "type": "performance"
}

Include remediation URLs from advisor results in the final report as clickable links.


Step 3: Audit Categories

3.1 Naming Conventions

RuleStandardCheck
Tablessnake_case, plural (users, posts)No camelCase, no singular
Columnssnake_case (created_at, user_id)No camelCase
Primary keysidNot user_id on own table
Foreign keys{referenced_table_singular}_id (user_id)Consistent pattern
Indexesidx_{table}_{column(s)}Descriptive names
Constraints{table}_{column}_{type} (users_email_unique)Descriptive names
Enumssnake_case type, UPPER_CASE valuesConsistent casing
Boolean columnsis_ or has_ prefix (is_active, has_access)Clear intent

Audit query:

SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
 AND (table_name ~ '[A-Z]' OR table_name !~ 's$');

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'public' AND column_name ~ '[A-Z]';

3.2 Data Types

RuleStandard
Primary keysuuid with gen_random_uuid() or cuid
Timestampstimestamptz (NOT timestamp)
Moneynumeric(12,2) or bigint (cents) — NEVER float/real
Emailtext with CHECK constraint or citext
Status/enumPostgres enum type or text with CHECK
JSONjsonb (NOT json)
Short stringstext preferred over varchar(n) in Postgres
Booleansboolean with NOT NULL DEFAULT
IP addressesinet type
ArraysNative text[], integer[] where appropriate

Audit queries:

SELECT table_name, column_name, data_type FROM information_schema.columns
WHERE table_schema = 'public' AND data_type = 'timestamp without time zone';

SELECT table_name, column_name, data_type FROM information_schema.columns
WHERE table_schema = 'public'
 AND data_type IN ('real', 'double precision')
 AND (column_name LIKE '%price%' OR column_name LIKE '%amount%'
 OR column_name LIKE '%cost%' OR column_name LIKE '%balance%');

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'public' AND data_type = 'json';

3.3 Required Columns and Timestamps

Every table MUST have:

ColumnTypeDefaultNotes
iduuidgen_random_uuid()Primary key
created_attimestamptznow()NOT NULL
updated_attimestamptznow()NOT NULL, auto-trigger

Audit queries:

SELECT t.table_name,
 EXISTS(SELECT 1 FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.column_name = 'created_at') AS has_created_at,
 EXISTS(SELECT 1 FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.column_name = 'updated_at') AS has_updated_at
FROM information_schema.tables t
WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE';

SELECT event_object_table, trigger_name FROM information_schema.triggers
WHERE trigger_schema = 'public' AND action_statement LIKE '%updated_at%';

3.4 Constraints and Validation

ConstraintWhen Required
NOT NULLEvery column unless explicitly optional
UNIQUEEmails, slugs, external IDs, usernames
CHECKEnums, ranges, formats, positive numbers
DEFAULTBooleans, timestamps, status fields
FOREIGN KEYEvery relationship column
ON DELETECASCADE for owned data, SET NULL for optional refs, RESTRICT for critical

Audit queries:

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'public' AND column_name LIKE '%_id'
 AND is_nullable = 'YES' AND column_name != 'id';

SELECT c.table_name, c.column_name FROM information_schema.columns c
WHERE c.table_schema = 'public' AND c.column_name LIKE '%_id' AND c.column_name != 'id'
 AND NOT EXISTS (
 SELECT 1 FROM information_schema.key_column_usage kcu
 JOIN information_schema.table_constraints tc ON kcu.constraint_name = tc.constraint_name
 WHERE tc.constraint_type = 'FOREIGN KEY'
 AND kcu.table_name = c.table_name AND kcu.column_name = c.column_name
 );

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'public' AND data_type = 'boolean' AND column_default IS NULL;

3.5 Indexes

RuleStandard
Foreign keysIndex on EVERY FK column
Frequent queriesIndex on WHERE/ORDER BY columns
Unique lookupsUnique index on email, slug, external_id
CompositeOrder: equality first, then range, then sort
RLS columnsIndex columns used in RLS policies
created_atDESC index for chronological queries
Partial indexesWHERE clause for subset queries

Audit query:

SELECT c.table_name, c.column_name FROM information_schema.columns c
WHERE c.table_schema = 'public' AND c.column_name LIKE '%_id' AND c.column_name != 'id'
 AND NOT EXISTS (
 SELECT 1 FROM pg_indexes i
 WHERE i.schemaname = 'public' AND i.tablename = c.table_name
 AND i.indexdef LIKE '%' || c.column_name || '%'
 );

SELECT t.table_name, COUNT(i.indexname) as idx_count
FROM information_schema.tables t
LEFT JOIN pg_indexes i ON i.tablename = t.table_name AND i.schemaname = 'public'
WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE'
GROUP BY t.table_name HAVING COUNT(i.indexname) <= 1;

3.6 Row Level Security (Supabase)

RuleStandard
RLS enabledEVERY public table has RLS ON
SELECT policyExists for every table
INSERT policyWITH CHECK on user ownership
UPDATE policyUSING + WITH CHECK on ownership
DELETE policyUSING on ownership
Service roleBypasses RLS (never expose to client)
Performance(select auth.uid()) subquery pattern
IndexesOn columns used in policies

Audit queries:

SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND rowsecurity = false;

SELECT t.tablename FROM pg_tables t
WHERE t.schemaname = 'public' AND t.rowsecurity = true
 AND NOT EXISTS (
 SELECT 1 FROM pg_policies p WHERE p.tablename = t.tablename AND p.schemaname = 'public'
 );

SELECT tablename, policyname, qual FROM pg_policies
WHERE schemaname = 'public'
 AND qual::text LIKE '%auth.uid()%'
 AND qual::text NOT LIKE '%(select auth.uid())%';

3.7 Relationships and Normalization

RuleStandard
3NF minimumNo transitive dependencies
Junction tablesFor many-to-many (user_roles, not JSON arrays)
No data duplicationNormalize repeated data into lookup tables
Cascade rulesDefined on every FK relationship
Self-referencingUse with parent_id pattern when needed
PolymorphicAvoid — use junction tables or STI instead

3.8 Migrations

RuleStandard
Sequential numberingTimestamps or 0001_, 0002_ prefixes
Descriptive names0003_add_user_roles.sql not 0003_update.sql
IdempotentIF NOT EXISTS, IF EXISTS guards
No data lossDown migrations or rollback plan
AtomicOne logical change per migration
No breaking changesAdditive first, then backfill, then cleanup

3.9 Security

RuleStandard
No plaintext secretsPasswords hashed, tokens encrypted
PII protectionSensitive columns identified and protected
Audit trailcreated_by, updated_by on sensitive tables
GrantsMinimal privileges per role
ExtensionsOnly necessary extensions enabled
Search pathExplicit schema references

Audit query:

SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'public'
 AND (column_name LIKE '%password%' OR column_name LIKE '%secret%'
 OR column_name LIKE '%token%' OR column_name LIKE '%ssn%'
 OR column_name LIKE '%credit_card%');

SELECT grantee, table_name, privilege_type FROM information_schema.table_privileges
WHERE table_schema = 'public' ORDER BY grantee, table_name;

Step 4: Full Schema Health Check (Single Query)

supabase:execute_sql
{
 "project_id": "<PROJECT_ID>",
 "query": "WITH table_info AS (SELECT t.table_name, EXISTS(SELECT 1 FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.column_name = 'id') AS has_id, EXISTS(SELECT 1 FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.column_name = 'created_at') AS has_created_at, EXISTS(SELECT 1 FROM information_schema.columns c WHERE c.table_name = t.table_name AND c.column_name = 'updated_at') AS has_updated_at, (SELECT rowsecurity FROM pg_tables pt WHERE pt.tablename = t.table_name AND pt.schemaname = 'public') AS rls_enabled, (SELECT COUNT(*) FROM pg_policies p WHERE p.tablename = t.table_name AND p.schemaname = 'public') AS policy_count, (SELECT COUNT(*) FROM pg_indexes i WHERE i.tablename = t.table_name AND i.schemaname = 'public') AS index_count FROM information_schema.tables t WHERE t.table_schema = 'public' AND t.table_type = 'BASE TABLE') SELECT table_name, CASE WHEN has_id THEN 'Y' ELSE 'N' END AS id, CASE WHEN has_created_at THEN 'Y' ELSE 'N' END AS created_at, CASE WHEN has_updated_at THEN 'Y' ELSE 'N' END AS updated_at, CASE WHEN rls_enabled THEN 'Y' ELSE 'N' END AS rls, policy_count AS policies, index_count AS indexes FROM table_info ORDER BY table_name"
}

Further reading

Frequently asked questions

What to verify before installation and use

What does the audit-db-schema source document cover?

Degree of freedom: MIXED — Steps 0, 1, 3 [HIGH freedom]; Steps 2 and 4 MCP/SQL probes [LOW freedom — run exactly] (run the query; do not invent a schema).

How do I install audit-db-schema?

The source record exposes this install command: npx skills add https://github.com/kensaurus/cursor-kenji --skill "skills/audit-db-schema". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged network in the source; the page lists the matching lines and excerpts.

Alternatives

Compare before choosing

Computed 9916

NintendaDev/unikit-ai

unikit-docs

Generate and maintain the project's TECHNICAL documentation from its codebase — scans the project structure, tech stack, and module boundaries, then writes a lean README landing page plus detailed topic pages (architecture, modules, setup, build, APIs), only the docs that are relevant. Use whenever the user wants to create, update, or validate documentation of the CODE or the project itself, e.g. "generate documentation", "create docs", "write the README", "update the project docs", "document th

Computed 9817

eugenelim/agent-ready-repo

work-loop

Use when implementing or resuming a non-trivial repository change: a feature, behavior-changing fix, refactor, migration, framework or dependency upgrade, schema or API change, performance work, infrastructure or build-system change, reversion, or an existing build spec under `docs/specs/`. Also use for bare continuation commands ('resume', 'continue', 'keep going', 'pick up where I left off', 'let's get going') when conversation or workspace context identifies active build work. Do not use for

Computed 9739

objectstack-ai/objectstack

objectstack-ui

Author ObjectStack UI metadata — Views (list/form/kanban/calendar/gantt), Apps (navigation), Pages (structured plus the HTML and React source-authoring tiers, ADR-0080/0081), Dashboards, Reports, Charts, Actions, and package Docs (`src/docs/*.md`). Use when the user is adding `*.view.ts` / `*.app.ts` / `*.dashboard.ts` / `*.action.ts` / `src/docs/*.md` files or designing a Studio-rendered UI surface, including dataset-bound dashboard/report widgets. Do not use for: data schema (see objectstack-d

Computed 976

mgiovani/cc-arsenal

team-review

Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r