Skip to main content

V1 Project Layout

Archived: This page describes the v1 flat-file project layout. For the current v2 folder-per-entity format, see Wren Project.

This guide explains the Wren MDL project structure, file formats, and typical workflow for managing your data models as a collection of YAML files. The Wren Project format makes it easy to version control your models, track changes, and separate connection information from model definitions.

A Wren MDL project is a directory of YAML files that makes MDL manifests human-readable and version-control friendly — similar to how dbt organizes models. Instead of managing a single large JSON file, each model lives in its own YAML file, and the project is compiled to a deployable mdl.json when needed.

YAML files use snake_case field names for readability. The compiled target/mdl.json uses camelCase, which is the wire format expected by ibis-server.

Project Structure

my_project/
├── wren_project.yml # Project metadata (catalog, schema, data_source)
├── models/
│ ├── orders.yml # One file per model
│ ├── customers.yml
│ └── ...
├── relationships.yml # All relationships
└── views.yml # All views

After building, the compiled file is written to:

my_project/
└── target/
└── mdl.json # Deployable MDL JSON (camelCase)

Connection info is managed via the MCP server Web UI (http://localhost:9001) — it is not stored in the project directory.


Project Files

wren_project.yml

The root metadata file describing the project:

name: my_project
version: "1.0"
catalog: wren
schema: public
data_source: POSTGRES
FieldDescription
nameProject name
catalogMDL catalog (matches the catalog in your MDL manifest)
schemaMDL schema
data_sourceData source type (e.g. POSTGRES, BIGQUERY, SNOWFLAKE)

models/<model_name>.yml

One file per model. Example for an orders model:

name: orders
table_reference:
catalog: ""
schema: public
table: orders
columns:
- name: order_id
type: INTEGER
is_calculated: false
not_null: true
is_primary_key: true
properties: {}
- name: customer_id
type: INTEGER
is_calculated: false
not_null: false
properties: {}
- name: total
type: DECIMAL
is_calculated: false
not_null: false
properties: {}
primary_key: order_id
cached: false
properties: {}

relationships.yml

All relationships between models in a single file:

relationships:
- name: orders_customer
models:
- orders
- customers
join_type: MANY_TO_ONE
condition: orders.customer_id = customers.customer_id

views.yml

All views in a single file:

views:
- name: recent_orders
statement: SELECT * FROM wren.public.orders WHERE order_date > '2024-01-01'
properties: {}

Field Mapping

When converting between YAML (snake_case) and JSON (camelCase):

YAML fieldJSON field
data_sourcedataSource
table_referencetableReference
is_calculatedisCalculated
not_nullnotNull
is_primary_keyisPrimaryKey
primary_keyprimaryKey
join_typejoinType

All other fields (name, type, catalog, schema, table, condition, models, columns, cached, properties) are identical in both formats.


Building the Project

Building compiles the YAML project into target/mdl.json:

# target/mdl.json — assembled MDL manifest (camelCase)

After building, deploy the MDL via the MCP server:

deploy(mdl_file_path="/workspace/target/mdl.json")

Or place it in the workspace before starting the container so it is auto-loaded via MDL_PATH.

Connection info is configured separately via the Web UI (http://localhost:9001) — it is not part of the build output.


Typical Workflow

1. Configure connection info

Open the Web UI at http://localhost:9001, select the data source type, and fill in connection credentials. Use /wren-connection-info in Claude Code for per-connector field reference.

2. Generate MDL

Run /generate-mdl in Claude Code. The skill uses MCP tools (list_remote_tables, list_remote_constraints) to introspect the database and build the MDL JSON.

3. Save project

Write wren_project.yml, models/*.yml, relationships.yml, and views.yml by converting the MDL JSON (camelCase) to snake_case YAML.

4. Add target/ to .gitignore

target/

5. Commit to version control

Commit the model YAML files — target/ is excluded.

6. Build

Read the YAML files, rename snake_case → camelCase, and write target/mdl.json.

7. Deploy

deploy(mdl_file_path="/workspace/target/mdl.json")

Migrating to v2

The v2 project layout uses a folder-per-entity structure with richer features (memory, instructions, profiles). To migrate:

Step 1 — Build mdl.json from the v1 project

If you have a v1 project, build it first to get the compiled JSON:

deploy(mdl_file_path="/workspace/target/mdl.json")

Or copy the target/mdl.json from your existing project. If you only have a raw mdl.json (e.g. from the MCP server), use that directly.

Step 2 — Install the Wren CLI

pip install "wren-engine[ui,memory]"

Step 3 — Convert JSON to v2 YAML project

Use --from-mdl to convert the camelCase JSON into a v2 folder-per-entity project:

wren context init --from-mdl /path/to/mdl.json --path my_project_v2

This produces:

my_project_v2/
├── wren_project.yml # schema_version: 2
├── models/
│ ├── orders/
│ │ └── metadata.yml # one directory per model
│ └── customers/
│ └── metadata.yml
├── views/
│ └── recent_orders/
│ └── metadata.yml # one directory per view
├── relationships.yml
└── instructions.md

Step 4 — Set up a profile and verify

wren profile add my-db --ui       # configure connection
wren context validate # check YAML structure
wren context build # compile to target/mdl.json
wren --sql "SELECT 1" # verify connection

Step 5 — Initialize memory

wren memory index

Your project is now on v2 with the full CLI workflow (profiles, memory, instructions). See Wren Project for the complete v2 reference.


Version Control Benefits

Storing MDL as a YAML project (rather than a single JSON blob) gives you:

  • Readable diffs — model changes show up as clear line-level diffs in pull requests
  • One file per model — merge conflicts are isolated to the affected model file
  • Separation of secrets — connection info lives in the Web UI, not in the project; target/ is gitignored
  • Reproducible buildstarget/mdl.json is always regenerated from source, never committed