30 KiB
CLI Reference
Default command — query
Running wren --sql '...' executes a query and prints the result. This is the same as wren query --sql '...'.
wren --sql 'SELECT COUNT(*) FROM "orders"'
wren --sql 'SELECT * FROM "orders" LIMIT 5' --output csv
wren --sql 'SELECT * FROM "orders"' --limit 100 --output json
Output formats: table (default), csv, json.
wren query
Execute SQL and return results.
wren query --sql 'SELECT order_id, total FROM "orders" ORDER BY total DESC LIMIT 5'
wren dry-plan
Translate MDL SQL to the native dialect SQL for your data source. No database connection required.
wren dry-plan --sql 'SELECT order_id FROM "orders"'
wren dry-plan --sql 'SELECT order_id FROM "orders"' -d postgres # explicit datasource, no connection file needed
wren dry-run
Dry-run SQL against the live database without returning rows. Prints OK on success, Error: <reason> on failure.
wren dry-run --sql 'SELECT * FROM "orders" LIMIT 1'
# OK
wren dry-run --sql 'SELECT * FROM "NonExistent"'
# Error: table not found ...
Overriding defaults
All flags are optional when ~/.wren/mdl.json and ~/.wren/connection_info.json exist.
The data source is always read from the datasource field in connection_info.json (or the inline --connection-info value). Only dry-plan accepts --datasource / -d as an override for transpile-only use without a connection file.
wren --sql '...' \
--mdl /path/to/other-mdl.json \
--connection-file /path/to/prod-connection_info.json
Or pass connection info inline:
wren --sql 'SELECT COUNT(*) FROM "orders"' \
--connection-info '{"datasource":"mysql","host":"localhost","port":3306,"database":"mydb","user":"root","password":"secret"}'
Both flat and envelope formats are accepted:
# Flat format
{"datasource": "postgres", "host": "localhost", "port": 5432, ...}
# Envelope format (auto-unwrapped)
{"datasource": "duckdb", "properties": {"url": "/data", "format": "duckdb"}}
wren profile import dbt
Import the active dbt target from profiles.yml into ~/.wren/profiles.yml.
wren profile import dbt --project-dir ./jaffle_shop
wren profile import dbt --project-dir ./jaffle_shop --target prod --name jaffle-prod
Common flags: --profiles-path, --profile, --target, --name, --no-activate.
wren context import dbt
Generate a Wren project from dbt artifacts.
wren context import dbt --project-dir ./jaffle_shop --path ./wren-jaffle
wren context import dbt --project-dir ./jaffle_shop --path ./wren-jaffle --dry-run
Requires target/manifest.json and target/catalog.json; run dbt build and dbt docs generate first. See dbt Integration.
wren context upgrade
Upgrade a project to the latest layout (schema_version 5). Forward-only and idempotent;
the v4→v5 step creates the knowledge/ skeleton.
wren context upgrade --dry-run # preview created/modified files
wren context upgrade # apply
wren context upgrade --to 5 # target a specific version
To migrate instructions.md and the LanceDB memory into knowledge/, see
Migration.
wren docs — Connection Info
wren docs connection-info <datasource>
Print the required and optional connection fields for a data source.
wren docs connection-info postgres
wren docs connection-info bigquery
wren docs connection-info snowflake
Use this to check which fields are needed before creating a profile.
wren memory — Schema & Query Memory
Schema and NL-SQL memory. NL→SQL pairs live in knowledge/sql/*.md (the source of truth);
the LanceDB index is a derived artifact rebuilt from them.
store, index, and recall work without any extra — pairs are written to and
searched over knowledge/sql/ directly (token/substring matching). Install the memory
extra only for semantic (embedding) recall and schema search (wren memory fetch):
pip install 'wrenai[memory]'
# or combine with main for the browser UI and interactive prompts:
pip install 'wrenai[memory,main]'
The backend is chosen automatically — LanceDB when the extra is installed, otherwise the
dependency-free grep backend. Force one with WREN_MEMORY_BACKEND=grep|lancedb. All
memory subcommands accept --path DIR to override the LanceDB storage location
(~/.wren/memory/).
Note: The
memoryextra bundles ~800MB of large unsigned native libraries (lancedb plus sentence-transformers/torch). On macOS, the first command that loads the memory stack can trigger a one-time XProtect/Gatekeeper scan and pause for up to about a minute before it finishes; this is normal macOS behavior, not a Wren error, and happens once per install or fresh virtual environment. With lazy memory loading, lightweight non-memorycommands are unaffected — the scan is deferred to your first real memory use, not eliminated.
Hybrid strategy: full text vs. embedding search
When providing schema context to an LLM, there is a trade-off:
- Small schemas — the full plain-text description fits easily in the LLM context window and gives better results because the LLM sees the complete structure (model-column relationships, join paths, primary keys) rather than isolated fragments from a vector search.
- Large schemas — the full text exceeds what is practical to send in a single prompt, so embedding search is needed to retrieve only the relevant fragments.
wren memory fetch automatically picks the right strategy based on the character length of the generated plain-text description:
| Schema size | Threshold | Strategy |
|---|---|---|
| Below 30,000 chars (~8K tokens) | Default | Returns full plain text |
| Above 30,000 chars | Default | Returns embedding search results |
The threshold is measured in characters (not tokens) because character length is free to compute, while accurate token counting requires a tokeniser. The 4:1 chars-to-tokens ratio holds for English; CJK text compresses less (~1.5:1), so a CJK-heavy schema switches to embedding search sooner — which is the conservative direction.
The default threshold (30,000 chars) can be overridden with --threshold.
wren memory index
Build the semantic index: schema items (models, columns, relationships, views) plus the
NL→SQL pairs from knowledge/sql/*.md (re-running converges on the markdown). Requires the
memory extra. Without it, the grep backend reads knowledge/sql/ directly, so there is
nothing to build and this command is a no-op.
wren memory index # uses ~/.wren/mdl.json
wren memory index --mdl /path/to/mdl.json # explicit MDL file
wren memory watch
Watch project sources and auto-reindex on change, so semantic recall never serves a
stale schema while you are actively modelling. Polls target/mdl.json and
knowledge/sql/*.md on an interval; when their content fingerprint changes it runs the
equivalent of wren memory index. A reindex that fails leaves the change pending and is
retried on the next poll — an update is never silently dropped. Runs until Ctrl+C.
Requires the memory extra (the index it maintains is LanceDB-backed). With the grep
backend there is no derived index to keep fresh, so this command exits with a message.
| Flag | Description |
|---|---|
--interval, -i |
Seconds between polls (min 1). Default: 5. |
--reindex-on-start / --no-reindex-on-start |
Reindex once on startup before watching. Default: off. |
--max-polls |
Stop after N polls (mainly for scripting/testing). Default: run until Ctrl+C. |
--mdl |
Explicit MDL file (must live under the watched project root). |
--path |
Project root to watch. Defaults to the discovered project. |
wren memory watch # poll every 5s, reindex on change
wren memory watch -i 2 # poll every 2s
wren memory watch --reindex-on-start # ensure the index is fresh before the first interval
wren memory describe
Print the full schema as structured plain text. No embedding or LanceDB required — this is a pure transformation of the MDL manifest into a human/LLM-readable format.
wren memory describe # uses ~/.wren/mdl.json
wren memory describe --mdl /path/to/mdl.json
wren memory fetch
Get schema context for an LLM. Automatically chooses the best strategy based on schema size: full plain text for small schemas, embedding search for large schemas.
When using the search strategy, optional --type and --model filters narrow the results.
wren memory fetch -q "customer order price"
wren memory fetch -q "revenue" --type column --model orders
wren memory fetch -q "order date" --threshold 50000 --output json
| Flag | Description |
|---|---|
-q, --query |
Search query (required) |
--mdl |
Path to MDL JSON file |
-l, --limit |
Max results for search strategy (default: 5) |
-t, --type |
Filter: model, column, relationship, view (search strategy only) |
--model |
Filter by model name (search strategy only) |
--threshold |
Character threshold for full vs search (default: 30,000) |
-o, --output |
Output format: table (default), json |
wren memory store
Store a natural-language-to-SQL pair. Writes knowledge/sql/<slug>.md (the source of
truth, no extra required), then indexes it into LanceDB when the memory extra is present.
wren memory store \
--nl "show top customers by revenue" \
--sql "SELECT c_name, sum(o_totalprice) FROM orders JOIN customer GROUP BY 1 ORDER BY 2 DESC" \
--datasource postgres
wren memory recall
Search stored NL-SQL pairs — semantic similarity with the memory extra, token/substring
matching (grep) without it. Each hit is annotated with its knowledge/sql/*.md path.
wren memory recall -q "best customers"
wren memory recall -q "monthly revenue" --datasource mysql --limit 5 --output json
| Flag | Description |
|---|---|
-q, --query |
Search query (required) |
-l, --limit |
Max results (default: 3) |
-d, --datasource |
Filter by data source |
-o, --output |
Output format: table (default), json |
wren memory export
One-time migration: export an existing LanceDB query_history into knowledge/sql/*.md
(source, timestamp, and dedup preserved). Requires the memory extra to read LanceDB;
leaves LanceDB intact. See Migration.
wren memory export # query_history → knowledge/sql/*.md
wren memory export --include-seed # also export auto-generated seed pairs
wren memory check
Report drift between knowledge/sql/*.md and the derived index (which user pairs are not
indexed, or indexed without a markdown source).
wren memory check
wren memory status
Show index statistics: storage path, table names, and row counts.
wren memory status
# Path: /Users/you/.wren/memory
# schema_items: 47 rows
# query_history: 12 rows
wren memory reset
Drop the derived LanceDB index. Your knowledge/sql/*.md source files are preserved —
rebuild the index any time with wren memory index.
wren memory reset # prompts for confirmation
wren memory reset --force # skip confirmation
wren cube — Pre-aggregation Queries
For aggregation queries where the MDL defines cubes, use wren cube instead
of writing raw SQL. The translator produces correct GROUP BY, DATE_TRUNC,
and WHERE clauses from a structured input.
wren cube list
List all cubes in the loaded MDL with their measures and dimensions.
wren cube list
wren cube describe <name>
Pretty-print the full cube schema as JSON: baseObject, measures (with
expressions), dimensions, time dimensions, hierarchies.
wren cube describe revenue
wren cube query
Build a CubeQuery and translate it to SQL via wren-core, then execute through
the same path as wren --sql. Two input modes:
CLI flags:
wren cube query \
--cube revenue \
--measures total,order_count \
--dimensions status \
--time-dimension "order_date:month:2024-01-01,2025-01-01" \
--filter "status:eq:completed" \
--order-by "total:desc" \
--limit 100
JSON input (--from <file|->):
cat query.json | wren cube query --from -
| Flag | Description |
|---|---|
--cube |
Cube name (required unless using --from) |
--measures |
Comma-separated measure names (required unless using --from) |
--dimensions |
Comma-separated dimension names |
--time-dimension |
<name>:<granularity>[:start,end] — one time dimension with optional date range |
--filter |
Repeatable. <dimension>:<operator>[:value]. For in / not_in, value is comma-separated. |
--order-by |
Repeatable. <member>:<direction> where direction is asc or desc; comma-separated for multiple. The member must be selected by the query. |
--limit / --offset |
Pagination |
--from <file|-> |
Load CubeQuery as JSON from a file or stdin. It supplies the whole query, so the query-building flags above — --order-by included — are ignored. |
--sql-only |
Print the generated SQL and exit without executing |
--mdl |
Path to MDL JSON (defaults to <project>/target/mdl.json) |
--output |
table (default), json, csv |
Supported granularities: year, quarter, month, week, day, hour, minute.
Supported filter operators: eq, neq, in, not_in, gt, gte, lt,
lte, contains, starts_with, is_null, is_not_null.
Ordering: --order-by sorts by the query's selected members, so pair it with
--limit for a genuine top-N. Omitting it keeps the default ordering (by the time
dimension when one is present). Directions are lowercase only, and a member listed
twice — or one the query does not select — is rejected by wren-core.
See the Cube guide for YAML structure and validation rules.
wren serve — MCP Server
Serve the project's query, schema, and knowledge tools to MCP clients (Claude
Desktop/Code, Cursor, any MCP-capable IDE) as a local MCP server. The server
embeds the engine in-process — no ibis-server, no separate backend — so it
runs from a bare project checkout as long as wren context build has run.
wren serve mcp
wren serve mcp # stdio (default) — client spawns this as a child process
wren serve mcp --transport http --port 8080 # local Streamable HTTP for multiple / remote clients
Requires the mcp extra: pip install 'wrenai[mcp]'.
| Flag | Default | Description |
|---|---|---|
--transport |
stdio |
stdio or http |
--host |
127.0.0.1 |
Bind host, --transport http only |
--port |
8080 |
Bind port, --transport http only |
--project |
discovered | Override project root |
--profile |
active profile | Connection profile name |
--allow-write |
off | Enable the store_query write tool |
--no-connect |
off | Transpile-only mode: disable run_sql, dry_run, query_cube |
--quiet / -q |
off | Suppress the client-registration help banner |
On startup the server prints (to stderr) ready-to-copy registration commands for
the running invocation — a claude mcp add / codex mcp add command for
--transport http, and those plus a JSON mcpServers config block for stdio
(reflecting --project, --profile, --allow-write, and WREN_HOME). Pass
--quiet to suppress it.
Requires target/mdl.json to exist (wren context build first) — errors with
a hint otherwise. If project source files (models/, views/, cubes/,
relationships.yml, wren_project.yml) are newer than target/mdl.json, it
warns that the MDL may be stale but still serves it — it never auto-builds.
Client wiring (stdio)
{
"command": "wren",
"args": ["serve", "mcp"],
"cwd": "/path/to/project"
}
For --transport http, connect the client to the Streamable HTTP endpoint at
http://<host>:<port> instead of spawning a process. Binds to 127.0.0.1 by
default; there is no bearer-token auth in this version — treat it as local-only.
Tools
| Group | Tools |
|---|---|
| Query | run_sql, dry_run, dry_plan, query_cube |
| Schema | get_mdl, list_models, describe_model, get_data_source, list_cubes, describe_cube, list_functions |
| Knowledge | get_instructions, recall_queries, get_context, describe_schema, list_stored_queries, list_knowledge |
Write (--allow-write) |
store_query |
run_sql, dry_run, and query_cube are disabled under --no-connect.
store_query is only registered when --allow-write is passed.
The knowledge tools degrade gracefully without the memory extra:
get_context (semantic schema retrieval, the schema-axis twin of
recall_queries) falls back to the full plain-text schema description;
describe_schema (the human-readable counterpart to get_mdl) needs no
optional dependency at all; list_stored_queries enumerates every NL→SQL
pair (not just a semantic top-k) from knowledge/sql/*.md; list_knowledge
lists every file readable via the wren://knowledge/{path} resource below.
Resources & prompt
wren://mdl— compiled MDL JSONwren://instructions— business rules fromknowledge/rules/*.mdwren://project— project name / catalog / schema / data source / schema_version / knowledge_schema_versionwren://agents— the project'sAGENTS.md, if presentwren://knowledge/{path}— read any file underknowledge/(e.g.wren://knowledge/knowledge.yml,wren://knowledge/rules/general.md); rejects any path that escapes the project'sknowledge/directorywren_workflowprompt — packages the schema → instructions → recall → dry-run → run_sql → query_cube → store SOP for a connecting agent
Security
Connection secrets are resolved from the profile once at server startup and never cross the MCP boundary — only SQL text, query results, and metadata are exposed to the client.
See the MCP guide for a walkthrough of wiring a client.
wren skills — Agent Workflow Guides
The CLI ships its own agent skill content. Use this on any AI client (the content is the same — content travels with the wheel, not the agent cache).
wren skills list
List the available workflow guides.
wren skills list
wren skills get <name>
Print a skill's main guide to stdout. Five names ship today:
onboarding, usage, generate-mdl, dlt-connector, enrich-context.
wren skills get onboarding # set up Wren end-to-end
wren skills get usage # day-to-day querying
wren skills get generate-mdl # MDL from a database schema
wren skills get dlt-connector # connect SaaS sources via dlt
wren skills get enrich-context # add business context (units, enums, cubes)
wren skills get <name> --full
Include the skill's reference docs inline (sorted, separated). For skills
that have no references/, the output is identical to the non---full form.
wren skills get <name> --script <s>
Print a bundled script's source to stdout. Currently:
wren skills get dlt-connector --script introspect_dlt > introspect_dlt.py
python introspect_dlt.py --duckdb-path ./pipeline.duckdb --output-dir ./project
wren ask — Prompt Shaping
Wrap a natural-language question in one of two bundled templates and print the rendered prompt to stdout. Does not execute any query — it produces a prompt for an agent to consume.
You must explicitly pick one mode (no default — silently changing a default would alter agent behavior across an upgrade).
wren ask "<question>" --guided
For weaker LLMs. Prepends a strict task flow (wren context show →
wren memory recall → write SQL → wren dry-plan → wren query).
wren ask "top 5 customers by revenue" --guided
wren ask "<question>" --direct
For stronger LLMs. Minimal wrapping; the agent decides which wren commands to run.
wren ask "monthly orders trend" --direct
wren genbi — Build & Deploy GenBI Apps
Turn a project's context layer into a shareable, browser-side GenBI web app
(powered by wren-core-wasm) and deploy it to Vercel or Cloudflare Pages.
CLI ↔ agent split: the CLI owns the authoritative build instruction and all
deterministic state (the app index, verify, deploy). The agent authors the app
code by following the instruction. .wren/apps.yml is only ever written by the
CLI — never by hand. The matching agent workflow guide is wren skills get genbi.
wren genbi build <name>
Print a project-hydrated build instruction (wasm wiring with the pinned
wren-core-wasm version, the project's model/column inventory, data-mode
guidance, acceptance criteria, and the target folder). Writes no app files; it
only compiles target/mdl.json first if it's missing.
wren genbi build sales-overview --prompt "orders dashboard" --data-mode snapshot
# --prompt-file <file> / --prompt - read a long prompt from a file or stdin
# --data-mode snapshot|live snapshot (default): bundle data with the app
# live: app calls a CORS endpoint at view time
wren genbi register <name> / list / remove <name>
Machine-written app index (<project>/.wren/apps.yml).
wren genbi register sales-overview --data-mode snapshot # record an authored app
wren genbi list # apps + status + deploy state
wren genbi remove sales-overview # drop index entry (files kept)
App names must be simple slugs (letters, numbers, _, -); names containing
path separators are rejected so they can't escape <project>/apps/.
wren genbi verify <name>
Deterministic deploy preflight (no browser): required files exist, mdl.json
parses, snapshot apps ship a .parquet/.duckdb asset, and a default-deny
secret scan flags inlined credentials. deploy gates on this. The secret scan
is best-effort defense-in-depth, not a guarantee — never inline secrets.
wren genbi open <name>
Serve a built app locally for preview (blocking; Ctrl-C stops).
wren genbi open sales-overview --port 8848 # 0 = auto-pick
wren genbi deploy <name>
Verify, then ship to the user's provider account and return a shareable URL.
Preview by default; --prod deploys to production (confirm with the user
first).
wren genbi deploy sales-overview --provider vercel # or cloudflare
wren genbi deploy sales-overview --provider vercel --prod
- Tokens are discovered from the environment or
.envfiles (VERCEL_TOKEN/CLOUDFLARE_API_TOKEN) — never passed as CLI flags. Cloudflare also needsCLOUDFLARE_ACCOUNT_ID. - Cloudflare shells out to the
wranglerCLI (npm install -g wrangler, or havenpxavailable) — Pages has no single inline-upload REST endpoint. - Vercel Deployment Protection: new Vercel projects return HTTP 401 to logged-out visitors by default. To make the URL public, disable it at Project → Settings → Deployment Protection. The deploy itself succeeded; the URL is just gated.
wren cloud — Connect a Project to Wren Cloud
Binds a local Wren project to a Wren Cloud project's git repository. The
binding is the git remote — nothing on your machine records which project a
directory belongs to. After binding, plain git push / git pull / git diff
are the commands; none of the security depends on going through this CLI again.
Two credentials, two lifetimes:
- The project API key is durable. It is prompted for once, stored under
~/.wren/cloud.yml(mode0600, keyed by git host + project id), and never leaves the machine except as anAuthorizationheader. - A git token is a short-TTL JWT minted from that key on every git operation, by a credential helper git invokes itself. It is never written to disk, so an expired token is a non-event — nothing ever holds one long enough to present it late.
--host means different things in different commands, and only defaults where
it names a target. On auth add and create it defaults to
https://cloud.getwren.ai — pass a URL for a self-hosted deployment. On link
and auth remove it selects among stored credentials and has no default,
deliberately: defaulting a filter would hide a credential you do have. Either
way, https is assumed when no scheme is given.
--git-host is only for deployments where the API and the git server are on
different hosts — a self-hosted setup with no single ingress in front of both.
On the managed service, leave it out.
wren cloud auth add
Store the credential git will authenticate with, and configure git to use it. Touches no directory, so it works before any clone exists.
wren cloud auth add --project 1234
wren cloud auth add --project 1234 --host https://wren.internal.example.com
Writes a URL-scoped credential-helper entry into your global git config (there is no clone yet to write a local one into). Because the helper resolves which project's token to mint from the path git hands it, one entry per host serves every project on it.
Refuses up front if the wren on PATH cannot serve the helper — a stored
credential that git cannot use is worse than none.
wren cloud create
Turn a Wren project you already have into a Wren Cloud project: create it, connect its data source, bind this directory, and push — the push is what deploys the models.
wren cloud create --org 42 --type BIG_QUERY --connection-info-file ./conn.json
wren cloud create --org 42 --type POSTGRES --connection-info '{"host":"db","port":"5432","user":"u","password":"p","database":"d"}' --test-connection
The organization key comes from --org-key, the WREN_CLOUD_ORG_KEY
environment variable, or a prompt. It is used only to create the project and
mint that project's own key, and is never written to disk.
--type is case-insensitive, and the names are the API's own — note the
underscore in BIG_QUERY. --connection-info is passed through unchanged, so
its fields are the API's too, and they differ per data source.
It is not the shape wren profile uses, and nothing converts between them.
The API wants camelCase keys, and BigQuery credentials as the service-account
object; a profile has snake_case keys and credentials as a base64 string.
Passing a profile export is rejected.
For the accepted types and a worked connectionInfo example for each, see
Create a project → Database connectionInfo examples.
That page is the source of truth; this CLI does not keep its own copy of the
list, so a data source added there works here without a CLI release.
Requirements, all checked before anything is created, so a refusal leaves no half-made project behind:
- The directory is a Wren project (
wren_project.yml) whose YAML compiles. To start a brand-new project instead, create it in the Wren Cloud web UI. --typeand a connection info are both given. A project without a data source is reported as still needing setup, and this CLI cannot attach one afterwards.- The directory is not already bound, does not sit inside another git repository, and git has an identity configured.
Models travel by git, not by the API: the manifest is built to validate the project and then discarded, and the push fires the repository's deploy hook.
wren cloud link
Bind a directory to a project you have already run auth add for. Use this to
clone a project onto a second machine, or to re-bind after unlink.
wren cloud link # current directory
wren cloud link ./my-project --project 1234
Safe to re-run if a previous attempt failed partway. If the directory is
already fully linked it says so and does not merge again — git pull is how you
get updates.
Names the local branch after the remote's default branch, so plain git push
works afterwards. Refuses to merge one project's history into another.
wren cloud unlink
Remove the origin remote. That is the entire unbind — no server call, and the
project is untouched.
wren cloud unlink
wren cloud unlink ./my-project --forget-key --yes
Your stored key is kept by default, since another directory may still be bound
to the same project. --forget-key drops it too, and removes that host's
credential-helper entry — but only once no stored login uses that host, because
the entry is shared by every project on it.
wren cloud auth list
Show what is stored, without showing the keys.
wren cloud auth list
PROJECT API HOST (--host) GIT HOST (git talks to) REPO
1234 https://cloud.getwren.ai https://cloud.getwren.ai org/42/1234/shared-data.git
Both host columns are printed because they mean different things and can
differ. --host on the other commands is the API host — the value you gave
auth add. The credential file is keyed by the git host instead, because
that is all git hands the credential helper, so reading the file to find a
value for --host gives you the wrong one. This command is the answer to that.
No flag prints a key.
wren cloud auth remove
Drop a stored credential. Touches no directory.
wren cloud auth remove --project 1234 --yes
wren cloud git-credential
The credential helper auth add wires into git. Git invokes it; you do not.