LLMSchema: simple database docs for AI agents
Last year I made LLMSchema, a tool for generating simple DB-schema markdown documentation for AI agents.
Without any explicit DB-schema documentation, AI agents will often infer your schema from migration files and code. In any database-backed application, the data-model is such a core piece of context that it should be easily available to AI agents in a suitable format.
LLMSchema extracts a PostgreSQL, MySQL, or SQLite schema into simple concise markdown documentation, covering each table’s columns, types, indexes, constraints and relationships.
# Use an exported database URL
export DATABASE_URL="postgres://user:pass@localhost:5432/mydb"
llmschema -o schema.md
# Or pass it directly
llmschema --db-url "postgres://user:pass@localhost:5432/mydb" -o schema.md
Example output
# Database Schema
**Database:** PostgreSQL 16.14 (Debian 16.14-1.pgdg13+1)
**Name:** `testdb`
**Conventions:** `PK` and `UNIQUE` identify unique keys; their backing indexes are omitted from Additional indexes.
**Tables:**
- [users](#users)
- [orders](#orders)
## users
| Column | Type |
|--------|------|
| id | PK integer NOT NULL DEFAULT nextval('users_id_seq'::regclass) |
| username | varchar(50) NOT NULL UNIQUE |
| email | varchar(100) NOT NULL |
| status | user_status (active, inactive, banned) DEFAULT 'active'::user_status |
| created_at | timestamp DEFAULT CURRENT_TIMESTAMP |
### Additional indexes
- idx_users_email on (email)
## orders
| Column | Type |
|--------|------|
| id | PK integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass) |
| user_id | integer NOT NULL |
| total_amount | numeric NOT NULL |
| order_date | timestamp DEFAULT CURRENT_TIMESTAMP |
| status | order_status (pending, processing, shipped, delivered, cancelled) DEFAULT 'pending'::order_status |
### Additional indexes
- idx_status on (status)
- idx_user_date on (user_id, order_date)
### References
- user_id → users.id (many orders to one users; ON DELETE CASCADE)
Database Schema
Database: PostgreSQL 16.14 (Debian 16.14-1.pgdg13+1)
Name: testdb
Conventions: PK and UNIQUE identify unique keys; their backing indexes are omitted from Additional indexes.
Tables:
users
| Column | Type |
|---|---|
| id | PK integer NOT NULL DEFAULT nextval('users_id_seq'::regclass) |
| username | varchar(50) NOT NULL UNIQUE |
| varchar(100) NOT NULL | |
| status | user_status (active, inactive, banned) DEFAULT 'active'::user_status |
| created_at | timestamp DEFAULT CURRENT_TIMESTAMP |
Additional indexes
- idx_users_email on (email)
orders
| Column | Type |
|---|---|
| id | PK integer NOT NULL DEFAULT nextval('orders_id_seq'::regclass) |
| user_id | integer NOT NULL |
| total_amount | numeric NOT NULL |
| order_date | timestamp DEFAULT CURRENT_TIMESTAMP |
| status | order_status (pending, processing, shipped, delivered, cancelled) DEFAULT 'pending'::order_status |
Additional indexes
- idx_status on (status)
- idx_user_date on (user_id, order_date)
References
- user_id → users.id (many orders to one users; ON DELETE CASCADE)
I keep the docs tracked by git and reference the generated markdown docs in AGENTS.md or CLAUDE.md, such that agents can pull it into context on demand. To keep the docs up to date, I piggyback the generation command with the database migration commands when running in local development, such that the markdown docs are kept up to date.
Installation instructions and examples are available in the LLMSchema repository.
Get new posts by email. No spam, unsubscribe any time.