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.yml and set schema_version to 5 for compatibility with the current WrenAI compiler.
  • Create models under models/<name>/metadata.yml using either table_reference for physical tables or ref_sql for 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.yml to expose curated SELECT statements with automatic schema inference.
  • Compile your custom MDL manifest files with wren context build to produce the target/mdl.json consumed 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →