CLI Reference¶
The medallion command is the entry point for all pipeline operations. It is installed as a console script when you pip install openmedallion.
Quick reference
For every command and flag on one page without the prose, see the Command Cheatsheet.
Commands¶
| Command | Purpose |
|---|---|
init |
Scaffold a new project directory |
run |
Execute the pipeline for a project |
query |
Ask a natural-language question directly in the terminal |
ask |
Start the neuron FastAPI server (/query, /feedback, /history, /session/end, /health, /docs) |
cortex |
Start the cortex Dash chat UI (chat, table, dashboard, history tabs) |
metadata |
Generate / approve / refresh metadata.yaml (RAG accuracy) |
relationships |
Generate / approve / render relationships.yaml (RAG accuracy) |
examples |
Generate / approve / harvest / review / eval synthetic Q→SQL examples (RAG accuracy) |
See Per-person chat history for --user, session_id, and the session-end curation loop.
init¶
Scaffold a new project folder with YAML config templates and Python UDF stubs.
Arguments:
| Argument | Description |
|---|---|
project |
Project name. Creates <project>/ in the current directory. |
What it creates:
<project>/
├── main.yaml # pipeline name, paths, bi_export
├── backend/
│ ├── bronze.yaml # source connection + incremental config
│ ├── silver.yaml # rename + cast + UDF template
│ ├── gold.yaml # group_by aggregation template
│ └── udf/
│ ├── silver/
│ │ ├── base.py # Silver base-table UDF stub
│ │ └── derived.py # Silver derived-table UDF stub
│ └── gold/
│ └── transforms.py # Gold pre-agg UDF stub
├── frontend/ # dashboard files (Tableau, Power BI, etc.)
├── data/ # gitignored pipeline outputs
├── summary/ # analysis write-ups
├── kestra_flow.yml # Kestra orchestration flow
└── README.md # pre-filled project documentation template
If the project folder already exists, the command aborts with an error and prints the path to delete to reinitialise.
Example:
medallion init sales_project
# 🏗️ Scaffolding project 'sales_project' ...
# ✅ Project 'sales_project' initialised.
run¶
Execute the pipeline for a named project.
Arguments:
| Argument | Description |
|---|---|
project |
Project name (must match a folder under --projects). |
Options:
| Flag | Default | Description |
|---|---|---|
--layer |
gold |
Which layer to run up to and including. One of: bronze, silver, gold, export, explore. |
--projects |
. |
Projects root directory. Override when running from a different working directory. |
Layer behaviour:
--layer |
Nodes executed | Use when |
|---|---|---|
bronze |
config → bronze | Testing ingestion only; inspecting raw data |
silver |
config → silver (bronze skipped) | Re-running transforms without re-ingesting |
gold |
config → gold (bronze + silver skipped) | Re-running aggregations only |
export |
Full pipeline | Production run including BI export |
explore |
Reads existing Parquet, generates reports | Generate data-quality / exploration HTML reports |
Layer skipping uses overrides
When --layer silver or --layer gold is specified, existing bronze/silver Parquet files are discovered and injected as Hamilton overrides. The upstream nodes are not re-executed. See Architecture — Skipping layers.
Examples:
# Full pipeline (bronze → silver → gold)
medallion run sales_project
# Ingest only
medallion run sales_project --layer bronze
# Re-run transforms after editing a UDF
medallion run sales_project --layer silver
# Projects in a non-default directory
medallion run sales_project --projects /var/pipelines/projects
query¶
Ask a natural-language question about a project's silver/gold data, directly in the
terminal — runs the full cerebrum pipeline locally, no server needed. Requires
pip install "openmedallion[cerebrum]".
medallion query <project> "<question>" [--projects PATH] [--model MODEL] [--provider PROVIDER] [--detect-ambiguity] [--decompose] [--use-templates] [--user NAME]
| Flag | Default | Description |
|---|---|---|
--projects |
. |
Projects root directory |
--model |
from settings / llama3.2 |
Model identifier |
--provider |
from settings / ollama |
LLM backend: ollama | openrouter | openai | custom |
--detect-ambiguity |
off | One extra, dedicated LLM call checks whether the question is ambiguous before any SQL generation is attempted. A second, always-on mechanism (no flag) already does this for free — see below; this flag adds a guaranteed check independent of it. |
--decompose |
off | One extra LLM call checks whether the question contains independent sub-questions; each runs through the pipeline separately if so |
--use-templates |
off | A high-confidence match to a curated templated: true example (see Template-Routed Query Layer) skips SQL generation entirely — the LLM only fills the template's declared {param} slots. Off by default; the filled SQL still goes through the same validation/execution safety net as any other query. |
--user |
OS username (getpass.getuser()) |
Display name chat history is recorded under — see Per-person chat history below |
Always on, no flag needed: the main SQL-generation prompt itself instructs the LLM
to respond CLARIFY: <question> instead of guessing when the schema doesn't
disambiguate the question — checked on the same call every query already makes, zero
extra cost. Both this and --detect-ambiguity raise the same AmbiguousQuestionError
(❓ Your question is ambiguous: ...). Relies on the model following the instruction —
not a guarantee with smaller local models. See
RAG Accuracy
for the full design.
If a project has status: approved tables in metadata.yaml and/or
verified: true examples in examples/synthetic.jsonl, they're picked up
automatically — see RAG Accuracy for the full design
(dynamic few-shot retrieval, confidence-gated schema pruning).
medallion query sales_project "What are the top 5 products by revenue?"
medallion query sales_project "Show monthly trends" --model mistral
medallion query sales_project "Headcount by dept and revenue by region" --decompose
medallion query sales_project "Which rep leads in revenue?" --user alice
Every question — success or failure — is appended to
<project>/chat_history/<user>.jsonl (best-effort; a logging failure never
blocks the answer). One --user-less invocation = one CLI session (a fresh
session_id per run) — there's no thumbs-up UI on the CLI path, so these
turns stay unrated (accepted: null) unless promoted manually.
Per-person chat history¶
Every /query call (from cortex or medallion query) is logged to
<project>/chat_history/<username>.jsonl — a personal audit trail, UI/audit
only, never fed back into the LLM prompt. username is a plain display
name, not real auth: cortex asks for one once (persisted in the browser's
localStorage), sent as an X-Medallion-User header; orthogonal to the
optional MEDALLION_API_KEY bearer gate.
Each turn also carries a session_id (ephemeral — one per browser tab or
CLI invocation, additive to username) and a three-state accepted field:
true/false only ever come from an explicit cortex 👍/👎 (never inferred
from interaction — a guessed satisfaction signal risks reinforcing
plausible-looking-but-wrong SQL), null means no feedback was given and
stays excluded from the learning loop forever.
Closing a session (POST /session/end) is a curation-promotion
trigger, not a data-sync call — chat_history is already written
server-side in real time on every /query. It rolls that session's rated
turns into the existing examples/harvested.jsonl/failures.jsonl (which
medallion examples harvest/review already consume — see
examples below). In cortex, a session closes via an explicit
"End Session" button, a 5-minute idle timeout, or a best-effort tab-close
beacon (navigator.sendBeacon — can't carry an Authorization header, so
this path only works when MEDALLION_API_KEY is unset).
cortex also has a "History" tab listing your own past turns, with a "↻ Reuse" button per entry that reloads the question into chat.
ask¶
Start the neuron FastAPI server, exposing cerebrum over HTTP for cortex (or any
HTTP client) to call. Requires pip install "openmedallion[cerebrum]".
| Endpoint | Purpose |
|---|---|
POST /query |
Ask a question — same pipeline as medallion query. Body: {question, project, use_templates} (use_templates defaults false). Logs a chat_history turn (success or failure); returns a turn_id for later /feedback. |
POST /feedback |
Record cortex 👍/👎 — sets the matching chat_history turn's accepted field in place (three-state: true/false/null, never inferred). Does not write examples/harvested.jsonl/failures.jsonl directly — see /session/end. |
GET /history?project=X |
Return the calling person's own past turns (cortex's "History" tab). |
POST /session/end |
Curation-promotion trigger, not a data sync (chat_history is already written in real time). Rolls a closed session's rated turns into examples/harvested.jsonl/failures.jsonl, which medallion examples harvest/review consume. |
GET /health |
Liveness check |
GET /docs |
Swagger UI |
cortex¶
Start the cortex Dash chat UI, which talks to a running neuron server over HTTP.
Three tabs: chat (with 👍/👎 feedback on every reply), table, and dashboard, with CSV/Excel download.
metadata¶
Manage a project's metadata.yaml — curated table/column descriptions used for
schema pruning (see RAG Accuracy).
medallion metadata generate <project> [--projects PATH] [--model MODEL] [--provider PROVIDER] [--profile]
medallion metadata approve <project> [--projects PATH]
medallion metadata refresh <project> [--projects PATH] [--model MODEL] [--provider PROVIDER] [--check] [--profile]
| Subcommand | Purpose |
|---|---|
generate |
LLM-draft metadata.yaml for silver/gold tables not yet status: approved. Approved tables are always skipped and preserved untouched. Requires [cerebrum]. |
approve |
Interactive [a]pprove / [s]kip / [q]uit review of draft/stale tables — no LLM call. |
refresh |
Detect schema drift (live Parquet vs. the schema_hash stored in metadata.yaml) and re-draft only affected/unapproved tables. An approved table that drifts is flipped to status: stale without a new LLM draft — review again with approve or re-run refresh to redraft it. Dropped tables (Parquet no longer exists) are flagged, never deleted. --check runs drift detection only (no LLM call, no write) and exits 1 if any table is drifted/dropped — useful in CI. Requires [cerebrum] (except --check, which makes no LLM call). |
medallion metadata refresh sales_project --check # CI gate: exit 1 if schema drifted
medallion metadata refresh sales_project # detect drift + re-draft affected tables
--profile — ydata-profiling enrichment (opt-in)¶
On generate and refresh, --profile enriches every freshly-drafted table's columns
with three additional fields, computed deterministically via
ydata-profiling (minimal=True — no
correlations/interactions) — zero extra LLM calls:
| Field | Populated when | Contains |
|---|---|---|
dtype |
always | ydata-profiling's inferred type: Numeric, Categorical, Boolean, DateTime, Text, ... |
stats |
always | null_pct, distinct_count, plus min/max/mean for Numeric columns |
accepted_values |
only for low-cardinality Categorical/Boolean columns (≤ 20 distinct values) |
the full sorted list of unique values — None for high-cardinality or numeric columns, to avoid dumping huge lists |
--profile is opt-in and off by default — the default path stays fast and
dependency-free. Approved-and-skipped tables are never profiled. Requires
pip install "openmedallion[profile]"; missing the dependency prints install
guidance instead of a raw traceback.
medallion metadata generate sales_project --profile
medallion metadata refresh sales_project --profile
relationships¶
Manage a project's relationships.yaml — explicit join paths between silver/gold
tables, detected via deterministic pattern matching (no LLM call for any subcommand).
medallion relationships generate <project> [--projects PATH]
medallion relationships approve <project> [--projects PATH]
medallion relationships erd <project> [--projects PATH] [--all]
| Subcommand | Purpose |
|---|---|
generate |
Detect relationships across silver/gold tables (FK naming, lineage, grain). |
approve |
Interactive review of draft/stale relationships. |
erd |
Render relationships as a Mermaid erDiagram to <project>/relationships_erd.md. Approved-only by default; --all includes draft/stale. Column types come from real Parquet dtypes, not metadata.yaml. No primary-key inference. |
examples¶
Manage a project's synthetic (question, sql) examples used for dynamic few-shot
retrieval (see RAG Accuracy).
medallion examples generate <project> [--projects PATH] [--count N] [--model MODEL] [--provider PROVIDER]
medallion examples approve <project> [--projects PATH] [--template]
medallion examples harvest <project> [--projects PATH]
medallion examples review <project> [--projects PATH]
medallion examples eval <project> [--projects PATH] [--model MODEL] [--provider PROVIDER] [--use-templates]
| Subcommand | Purpose |
|---|---|
generate |
LLM drafts (question, sql) pairs from approved metadata + relationships; each is validated (allowlist + DuckDB EXPLAIN) before being written. Requires [cerebrum]. |
approve |
Interactive review of unverified examples — no LLM call. With --template, reviews already-verified: true examples instead, for promotion to templated: true (see Template-Routed Query Layer) — auto-detects {slot} placeholders in the SQL and prompts for a description per slot. |
harvest |
Promotes examples/harvested.jsonl (cortex 👍) candidates into synthetic.jsonl as unverified — still needs approve. |
review |
Lists examples/failures.jsonl (cortex 👎) entries — a plain listing, no LLM call. |
eval |
Admin regression check: re-runs every verified: true example's question, executes both the stored ("golden") SQL and the freshly-generated SQL, and compares the results (not raw SQL text). Reports a ✅/❌ per question and a match summary — run this after curating metadata/relationships/examples to see whether it helped or hurt. With --use-templates, additionally re-runs each question through CerebrumPipeline(use_templates=True) and flags ⚠️ template-routing changed the result wherever that path's outcome diverges from the golden result — the regression signal for the template layer specifically. No model retraining happens anywhere in this project; this checks curation changes, not weight changes. Requires [cerebrum]. |
medallion examples approve sales_intel --template # promote a verified example to templated:true
medallion examples eval sales_intel --use-templates
Global Behaviour¶
- The CLI always reconfigures
sys.stdoutto UTF-8 so emoji output works on Windows. - All commands exit with a non-zero code on error (config validation failure, missing UDF file, etc.).
- Running
medallion --helpormedallion <command> --helpprints usage.