How to Write Custom MDL Manifest Files in WrenAI: Models, Relationships, and Views
WrenAI compiles YAML-based custom MDL manifest files into a camelCase JSON schema that powers the agent's understanding of your data warehouse.
The Canner/WrenAI repository uses a YAML-based Model Definition Language (MDL) to describe the logical schema that the AI agent queries against. When you write custom MDL manifest files, you create a version-controlled project structure that the CLI compiles into an engine-ready artifact. This guide covers the exact file paths, field names, and compilation steps used in the WrenAI source code.
Start with Project Metadata in wren_project.yml
Every MDL project begins at the root with a wren_project.yml file. This file sets the global layout version, namespace, and connection profile that the compiler expects.
schema_version: 5
name: my_project
version: "1.0"
catalog: wren
schema: public
data_source: postgres
profile: my-pg
The schema_version must match the current layout version—version 5—so the CLI knows how to parse the manifest according to the WrenAI reference documentation. The catalog and schema fields define WrenAI namespaces, not the underlying database catalog, while profile references a connection you previously set with wren context set-profile.
Define Models Using models/<model_name>/metadata.yml
Models live under models/<name>/metadata.yml and represent either a physical table or a SQL-defined dataset. Each model must declare its columns and, if it participates in TO_MANY traversals, a primary_key.
Map Physical Tables with table_reference
Use table_reference when a model maps directly to an existing database table. The primary_key field is required for any TO_MANY relationship traversals as implemented in the MDL schema reference.
name: customers
table_reference:
catalog: jaffle_shop
schema: main
table: customers
primary_key: customer_id
columns:
- name: customer_id
type: INTEGER
is_primary_key: true
not_null: true
- name: first_name
type: VARCHAR
- name: last_name
type: VARCHAR
- name: number_of_orders
type: BIGINT
Build Virtual Datasets with ref_sql
Alternatively, define a model with ref_sql to create a virtual dataset from a SELECT statement. You can write the SQL inline inside metadata.yml or place it in a sibling ref_sql.sql file, which takes precedence over the inline definition.
name: revenue_summary
ref_sql: |
SELECT DATE_TRUNC('month', order_date) AS month,
SUM(total) AS total_revenue
FROM orders
GROUP BY 1
columns:
- name: month
type: DATE
- name: total_revenue
type: DECIMAL
Join Models with relationships.yml
The relationships.yml file at the project root declares how two models join together. It contains a top-level relationships: list where each entry specifies the models, join type, and condition.
relationships:
- name: orders_customers
models:
- orders
- customers
join_type: MANY_TO_ONE
condition: orders.customer_id = customers.customer_id
Only equality conditions are supported, and the first model in the models list must appear on the left side of the condition string. Supported join types include MANY_TO_ONE, ONE_TO_MANY, and ONE_TO_ONE according to the MDL relationship specification.
Expose Curated Datasets with views/<view_name>/metadata.yml
Views provide reusable SQL SELECT statements that can reference models or other views, inheriting their schema automatically from the query result. Store the SQL inline under statement or in a sibling sql.yml file that overrides the inline version.
name: top_customers
statement: |
SELECT customer_id, SUM(total) AS lifetime_value
FROM wren.public.orders
GROUP BY 1
ORDER BY 2 DESC
LIMIT 100
properties:
description: "Top customers by lifetime value"
Build the Manifest with wren context build
WrenAI converts your YAML project into an engine-ready artifact during compilation. All YAML files use snake_case field names, and the build step translates them into camelCase inside target/mdl.json. Run the following commands from the project root:
wren context build # compiles YAML into target/mdl.json
wren memory index # builds the LanceDB index for knowledge (optional)
The generated target/mdl.json is what the Wren engine consumes, while your original YAML files remain under version control.
Summary
- Place project-wide settings in
wren_project.ymland setschema_versionto5for compatibility with the current WrenAI compiler. - Create models under
models/<name>/metadata.ymlusing eithertable_referencefor physical tables orref_sqlfor SQL-defined virtual datasets. - Define joins between models in
relationships.yml, ensuring equality conditions place the first listed model on the left side. - Add views under
views/<name>/metadata.ymlto expose curated SELECT statements with automatic schema inference. - Compile your custom MDL manifest files with
wren context buildto produce thetarget/mdl.jsonconsumed by the engine.
Frequently Asked Questions
What schema version does WrenAI require for custom MDL manifest files?
WrenAI requires schema_version: 5 in wren_project.yml so that the CLI knows how to compile the manifest layout into the correct engine format. Using an outdated version will cause the wren context build step to fail.
Can I extract SQL into separate files instead of using inline YAML?
Yes. For models, place SQL in a sibling ref_sql.sql file next to metadata.yml; for views, use a sibling sql.yml file. When present, these external files take precedence over any inline ref_sql or statement definitions.
Which join types are supported in MDL relationships?
The MDL schema supports MANY_TO_ONE, ONE_TO_MANY, and ONE_TO_ONE join types. Only equality conditions are permitted, and the first model listed in the models array must appear on the left side of the condition expression.
How does WrenAI handle case conversion during compilation?
All YAML source files use snake_case keys for readability. During the wren context build step, the compiler transforms these keys into camelCase inside the generated target/mdl.json that the engine queries against.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →