diff --git a/.gitignore b/.gitignore index 4d14de3..d432d14 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ dist/ *.log *.tgz .superpowers/ + +# demo output — regenerated by `vhs demo.tape`, only sources + demo.gif are tracked +demo/graph/ +demo/.claude/ +demo/AGENTS.md diff --git a/README.md b/README.md index 4bb1a66..66b77e1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ DBML → LLM-ready markdown knowledge graph. Reads a `.dbml` schema, merges an o business-context overlay, and writes a set of plain markdown files (plus a JSONL export) sized for AI coding agents to consume without any special tooling. +![dbmlgraph demo — generate, find, query, and install into an AI agent](https://raw.githubusercontent.com/verryp/dbmlgraph/main/demo/demo.gif) + +Recorded with [vhs](https://github.com/charmbracelet/vhs) from [`demo/demo.tape`](demo/demo.tape) against the sample schema in [`demo/`](demo). Regenerate with `npm run build && cd demo && vhs demo.tape`. + ## What / Why AI agents working against a database don't need raw DDL — they need schema *semantics*: diff --git a/demo/.dbmlgraph.yml b/demo/.dbmlgraph.yml new file mode 100644 index 0000000..a002a09 --- /dev/null +++ b/demo/.dbmlgraph.yml @@ -0,0 +1,3 @@ +input: schema.dbml +overlays: overlays/ +out: graph/ diff --git a/demo/demo.gif b/demo/demo.gif new file mode 100644 index 0000000..8551560 Binary files /dev/null and b/demo/demo.gif differ diff --git a/demo/demo.tape b/demo/demo.tape new file mode 100644 index 0000000..fcde996 --- /dev/null +++ b/demo/demo.tape @@ -0,0 +1,42 @@ +# vhs demo tape — regenerate with: cd demo && vhs demo.tape +# Requires: vhs (brew install vhs), dbmlgraph built at ../dist/cli.js + +Output demo.gif + +Set FontSize 15 +Set Width 1100 +Set Height 620 +Set Theme "Catppuccin Mocha" +Set TypingSpeed 40ms +Set Padding 16 + +Hide +Type `alias dbmlgraph="node ../dist/cli.js"; clear` +Enter +Show + +Type "# DBML schema + business-context overlay -> LLM-ready knowledge graph" +Enter +Sleep 800ms + +Type "dbmlgraph generate" +Enter +Sleep 2s + +Type "# where does promo_id live?" +Enter +Type "dbmlgraph find promo_id" +Enter +Sleep 3.5s + +Type "# full context for one table: columns, meanings, relationships" +Enter +Type "dbmlgraph query orders | head -30" +Enter +Sleep 5s + +Type "# wire it into your AI agent" +Enter +Type "dbmlgraph install claude" +Enter +Sleep 3s diff --git a/demo/overlays/orders.yml b/demo/overlays/orders.yml new file mode 100644 index 0000000..8ebfbaf --- /dev/null +++ b/demo/overlays/orders.yml @@ -0,0 +1,11 @@ +purpose: > + Order header. One row per checkout. +rules: + - Never delete; cancel via shipment status +columns: + customer_id: + meaning: Buyer who placed the order + billing_customer_id: + meaning: Payer when different from the buyer (gift orders, corporate billing) + promo_id: + meaning: Campaign applied at checkout; NULL = no discount diff --git a/demo/overlays/users.yml b/demo/overlays/users.yml new file mode 100644 index 0000000..fb71172 --- /dev/null +++ b/demo/overlays/users.yml @@ -0,0 +1,4 @@ +purpose: Account registry — one row per login identity. +columns: + email: + meaning: Login id, unique across the platform diff --git a/demo/schema.dbml b/demo/schema.dbml new file mode 100644 index 0000000..dac0488 --- /dev/null +++ b/demo/schema.dbml @@ -0,0 +1,80 @@ +// Fixture for `query`: wide enough for depth-2 hops, shared neighbors, +// and repeated refs between the same table pair. + +Enum shipment_status { + pending [note: 'not yet picked'] + in_transit + delivered +} + +TableGroup identity { + users + addresses +} + +Table users { + id bigint [pk, increment] + email varchar(100) [unique, not null, note: 'login id'] +} + +Table addresses { + id bigint [pk] + user_id bigint [not null, ref: > users.id] + line1 varchar(120) +} + +// ============================================================ +// DOMAIN 2: Commerce +// ============================================================ + +Table customers { + id bigint [pk] + user_id bigint [ref: > users.id] + Note: 'buyer profile' +} + +Table promotions { + id bigint [pk] + code varchar(20) [unique] + Note: 'discount campaign' +} + +Table categories { + id bigint [pk] + name varchar(60) +} + +Table products { + id bigint [pk] + category_id bigint [ref: > categories.id] + name varchar(120) [not null] + Note: 'sellable item' +} + +Table orders { + id bigint [pk] + customer_id bigint [not null, ref: > customers.id] + billing_customer_id bigint [ref: > customers.id] + promo_id bigint [ref: > promotions.id] + Note: 'order header' +} + +Table order_items { + id bigint [pk] + order_id bigint [not null, ref: > orders.id] + product_id bigint [not null, ref: > products.id] + promo_id bigint [ref: > promotions.id] + qty int [not null] + Note: 'one line per product on an order' +} + +Table shipments { + id bigint [pk] + order_id bigint [ref: > orders.id] + status shipment_status +} + +Table payments { + id bigint [pk] + order_id bigint [ref: > orders.id] +}