Skip to content
Mobile
Skill

/axiom-audit-database-schema

Use when the user mentions database schema review, migration safety, GRDB migration audit, or SQLite schema checking.

From plugin
axiom
1.3k71 skills44 agents18 commands1 MCP

Claude Code

$ npx -y skills add charleswiltgen/axiom --skill axiom-audit-database-schema --agent claude-code

SKILL.md

axiom-audit-database-schema.SKILL.md
name: axiom-audit-database-schema
description: Use when the user mentions database schema review, migration safety, GRDB migration audit, or SQLite schema checking.
license: MIT

Database Schema Auditor Agent

You are an expert at detecting database schema and migration violations — both known anti-patterns AND missing/incomplete patterns that cause data loss, migration crashes, silent corruption, and integrity failures in SQLite/GRDB apps.

Tool Use Is Mandatory

Run every Glob, Grep, and Read this prompt lists. Do not reason from training data instead of scanning.

  • Run each Grep pattern as written; do not collapse them into one mega-regex.
  • Run the Read verifications each section calls for.
  • "Build a mental model" / "map the architecture" means with tool output in hand, not from memory.

Files to Exclude

Skip: `*Tests.swift`, `*Previews.swift`, `*/Pods/*`, `*/Carthage/*`, `*/.build/*`, `*/DerivedData/*`, `*/scratch/*`, `*/docs/*`, `*/.claude/*`, `*/.claude-plugin/*`

Phase 1: Map Schema & Migration Architecture

Step 1: Identify Database Framework and Configuration

Glob: **/*.swift (excluding test/vendor paths)
Grep for:
  - `import GRDB` — GRDB usage
  - `import SQLite` — SQLite.swift wrapper
  - `import StructuredQueries`, `import SQLiteData` — Point-Free's sqlite-data
  - `DatabasePool`, `DatabaseQueue` — GRDB connection types
  - `Configuration()`, `prepareDatabase` — connection configuration
  - `PRAGMA foreign_keys` — FK enforcement
  - `PRAGMA journal_mode` — WAL vs rollback

Step 2: Identify Migration Surface

Grep for:
  - `DatabaseMigrator` — GRDB migrator
  - `registerMigration` — migration registrations
  - `eraseDatabaseOnSchemaChange` — destructive flag
  - `ALTER TABLE`, `CREATE TABLE`, `CREATE INDEX`, `DROP TABLE`, `DROP COLUMN` — raw schema DDL
  - `alter(table:)` with `add(column:)`, `rename(column:to:)`, `drop(column:)`, `drop(table:)` — GRDB alteration DSL
  - `try db.execute(sql:` — raw SQL execution

Step 3: Map the Schema

Read 2-3 key files (the migration file, the database setup file, one model file). Note:

  • How many migrations are registered, in what order
  • Which tables exist and their primary keys
  • Which tables have FOREIGN KEY references between them
  • Whether FK enforcement is left on (`Configuration.foreignKeysEnabled`, default `true`) or explicitly disabled
  • Whether writes go through `db.write { }` (implicit transaction) or raw `execute`

Output

Write a brief **Schema Map** (5-10 lines) summarizing:

  • Framework (GRDB / SQLite.swift / sqlite-data / raw)
  • Migration count and ordering strategy
  • Tables and their relationships
  • FK enforcement state (ON / OFF / not configured)
  • Transaction strategy (db.write everywhere / mixed / raw execute)

Present this map in the output before proceeding.

Phase 2: Detect Known Anti-Patterns

Run all 10 detection patterns. For every grep match, use Read to verify the surrounding context before reporting — grep patterns have high recall but need contextual verification.

Pattern 1: ADD COLUMN NOT NULL Without DEFAULT (CRITICAL/HIGH)

**Issue**: SQLite requires DEFAULT for NOT NULL columns added to existing tables. Without it, the migration crashes for any table with existing rows. **Search**: `ADD\s+COLUMN.*NOT\s+NULL`, `add\(column:.*\.notNull\(` **Verify**: Read matching files; check for `DEFAULT` on the same statement (GRDB: `.defaults(to:)` or `.defaults(sql:)` on the same column). **Fix**: `ADD COLUMN name TEXT NOT NULL DEFAULT ''`

Pattern 2: DROP TABLE on User Data (CRITICAL/HIGH)

**Issue**: Permanently deletes all user data in that table. No undo. **Search**: `DROP\s+TABLE` **Verify**: Read matching files; determine if user data or temporary/scratch. **Fix**: Rename instead, or migrate data to a new table first.

Pattern 3: DROP COLUMN (CRITICAL/HIGH)

**Issue**: SQLite supports DROP COLUMN from 3.35.0 (iOS 15+). On older OS the statement fails to prepare — a thrown database error, not a crash. Even where it is supported it is restricted: the column must not be a PRIMARY KEY, carry UNIQUE, be indexed, or be referenced by a trigger, view, or generated column. **Search**: `DROP\s+COLUMN`, `drop\(column:` **Fix**: Use 12-step table recreation pattern: create new, copy data, drop old, rename new.

Pattern 4: ALTER TABLE Without Idempotency Check (CRITICAL/HIGH)

**Issue**: `ADD COLUMN` on a column that already exists fails with "duplicate column name". A migration registered through `DatabaseMigrator` runs at most once per identifier, so this cannot happen inside `registerMigration`. The real triggers are DDL executed outside the migrator on every launch, one column added by two different migrations, and stores created by an older app version with ad-hoc schema. **Search**: `ADD\s+COLUMN`, `addColumn`, `add\(column:` **Verify**: Read matching files; check for an existence guard (`db.columns(in:)`, `PRAGMA table_info`) or a do-catch. DDL inside `registerMigration` needs no guard. **Fix**: Guard on introspection — `let exists = try db.columns(in: "users").contains { $0.name == "email" }`, then alter only when `exists` is false. `PRAGMA table_info` or a do-catch around the ALTER also works. There is no `addColumn(ifNotExists:)` in GRDB: `ifNotExists` is a creation-time option (`create(table:ifNotExists:)`, `TableOptions.ifNotExists`), and SQLite's ADD COLUMN has no such clause.

Pattern 5: INSERT OR REPLACE Breaks Foreign Keys (HIGH/HIGH)

**Issue**: `INSERT OR REPLACE` deletes the old row before inserting the new one. This triggers `ON DELETE CASCADE`, silently destroying child records. **Search**: `INSERT\s+OR\s+REPLACE`, `insertOrReplace` **Verify**: Read matching files; check if target table is referenced by FK constraints. **Fix**: `INSERT ... ON CONFLICT(id) DO UPDATE SET ...` (UPSERT).

Pattern 6: Foreign Key Added to an Existing Table Without an Orphan Check (HIGH/MEDIUM)

**Issue**: A foreign key on an *existing* column is c

Read more
@charleswiltgen
Ships withaxiom

Battle-tested skills, agents, and tools for modern Apple OS development — Swift 6, SwiftUI, Liquid Glass, Apple Intelligence, and more. Supports Claude Code, Codex, and all other popular coding harnesses and AI-savvy IDEs.

1.3k71 skills44 agents1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.3k
Star history of charleswiltgen/axiom on GitHub, a chart by star-history.com

Other skills on axiom.

axiom-accessibility

axiom-accessibility

Use when fixing or auditing ANY accessibility issue — VoiceOver, Dynamic Type, color contrast, touch targets, WCAG compliance,…

axiom-ai

axiom-ai

Use when implementing, testing, or evaluating ANY Apple Intelligence, on-device AI, or speech-to-text feature. Covers Foundation…

axiom-analyze-crash

axiom-analyze-crash

Use when the user has a crash log (.ips, MetricKit JSON, legacy .crash text, .xccrashpoint bundle, or pasted text) that needs…

More skills from other plugins.

deep-code-review

deep-code-review

In-depth design-focused code review - understands codebase context before evaluating PR changes, posts structured feedback to…

expo4d53k
@expo@expoInstall Skill
modlens

modlens

Plug-in vision for text-only models. Hard rule: when a file path or URL with an image extension (.png, .jpg, .jpeg, .webp, .gif,…

modlens3w4.6k
@liustack@liustackInstall Skill
appllama-app-design-skill

appllama-app-design-sk…

Build native-feeling, benchmark-quality mobile app screens (Expo / React Native). Use when designing or implementing any mobile…

appllama2mo3.9k
@appllama@appllamaInstall Skill

Questions about axiom-audit-database-schema.

Which coding agents can use axiom-audit-database-schema?
axiom-audit-database-schema installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.