Airbyte at the door. dbt and DuckDB in the middle. MCP at the edge.
MetricMine is built from standard parts and sits between the tools you already run. This page says what each part does here, what is exercised today and what is not, and how the demo's patterns map to data of your own.
The front door
Bronze lands through PyAirbyte.
Nothing in the pipeline knows the demo's sources by name. Bronze lands whatever the source list names, the profiler measures whatever the profiling targets name, and the engine emits a category for every mapping contract. Airbyte publishes a catalog of 600+ connectors by its own count; PyAirbyte is the Python library that runs Airbyte connectors, and it is how bronze lands here.
What is exercised today: the file connector, seven files deep, with reader options declared per source. What is not: other connector types. The standing non-goal is one connector type, many files, and the site says so rather than implying more.
The warehouse
DuckDB, on purpose.
DuckDB is the local warehouse because the whole pipeline is meant to run on one machine, keyless, with no cluster and no account. What lives on the machine is a specification, not a silo: the contracts and the compiled context are warehouse-agnostic files in git, and every gold model is regenerated from them, so the data file is disposable and the meaning is portable.
dbt profiles carry the execution plane. A second adapter is an experiment in the project's lane, not a promise on this page. The transforms are plain dbt Core models with contracts enforced, so what a dbt engineer already knows applies without translation.
The edge
MCP, read-only, five tools.
Serving is read-only three layers deep: the connection opens read-only, the query tool accepts exactly one SELECT, and every result is row-capped with an explicit truncated flag. The demo guide wires the server into Claude Desktop.
Tool
What it answers
list_fact_categories
which fact categories exist, with row counts, the typed table to query, each category’s subject in the words of the people who approved its contracts, and the registry keys
get_schema
the declared field manifest behind a schema key
get_context
the full compiled context behind a schema key, in two named parts: data (what the columns are) and expert_context (what people wrote about them), plus the contract citation
query
one row-capped SELECT; anything else refuses, naming the failed check
lookup_record
every place a content key resolves: registry, fact, dimension, or a derived identity
Silver is human-owned SQL under contracts, because silver is where meaning is decided. That is the work Claude Code is good at when it starts grounded, and the repository ships the context to ground it. Gold is mechanical: the engine emits it the same way every time, and no model gets to improvise there.
Adding a source.
One file to fetch, four entries to declare, two contracts to write, one model, and a paste into the star contract. Everything else is generated by a command and reviewed. The walkthrough was validated by adding a source that is not in the demo to a fresh clone in under fifteen minutes, eight files by hand.
The scan derives a queue from the tree and names the next command per item; the describe stance drafts a contract for an existing model; verify-grain measures a declared grain rather than trusting it; enforce-properties adds only what the contract implies.
Oscar is the repository's resident guide, a read-only subagent. Ask it how the system works, where a task is done, what a rule means, or how to keep silver clean, and it answers with the file and the line. Ask for a review and it runs the nine-item checklist, from the all-or-nothing column rule to the never-weaken gate, and stops.
Every pattern in the demo maps to a situation you will recognize.
The demo sources were chosen because they carry these situations in miniature. Each one is a decision written into a contract, a measured completeness on a join, a floor in a rule, and a line in a gate.
Rows you are tempted to drop
Cancellations, returns, voids, soft deletes: retain and flag, state the consequence for every aggregate in the usage text, and let the consumer filter. Conservation against bronze then stays auditable.
Duplicates
Decide whether they are capture artifacts or events, write the decision as a property on the contract with the measured rate, and enforce the residual grain with an error-severity rule.
A reference newer than your events
A customer master, a product catalog, a location table refreshed after the transactions: declare the vintage on both contracts, measure the join completeness, set the floor just under it, and keep unresolved rows with null attributes.
Codes shared across systems
Customer ids, SKUs, site codes: conform them in silver with one normalization rule declared once and cited by every carrier, and let the gate refuse a key that only one table carries.
A series with gaps
Sensor readings, hourly rates, daily balances: declare the coverage with its count, and let the join completeness, not a silent inner join, show the effect.
Measurements absent when not observed
A gust, a discount, a reason code: say that null means not reported, not zero, in the field’s meaning, because an agent will read it.
Units and time zones
Units in column names; one UTC key for joining; local time as reading columns; the conformed calendar does the alignment.
Detail mixed with roll-ups
Economies and regional aggregates, accounts and their parents, SKUs and bundles: flag the roll-ups by an explicit list, never a name pattern, and say in the usage text what double counts.
When to unify and when to stand alone
Unify in silver when two sources describe the same entity and a question will need both columns on one row. Leave a category alone when it shares nothing, and let the star’s calendar align it in shape only.
What not to do: no shared entity dimension in gold; no join completeness that was not measured; no rows dropped without a recorded decision; no unit or null semantics that live only in someone's head. The full map: docs/sources-explained.md, section 10.
Fits when
The shape of a good fit.
Your data arrives as files or extracts, and you want the modeling and the meaning settled on one machine before anything is promoted anywhere.
You want an assistant to answer over governed data without a warehouse credential in its hands.
You want AI to draft the boring parts of modeling and a person to sign every change, with the record in git.
You want the meaning of the data to travel as files a team shares, and the data itself to be reproducible from them.
Does not fit when
The standing non-goals.
You need streaming, multi-tenancy, authentication, billing, or a hosted UI. Those are non-goals, written into the README and enforced as constraints.
You need a connector type other than the file connector. Other connector types are a standing non-goal today, not a roadmap item.
You need a warehouse other than DuckDB today. A second adapter is an experiment in the project's lane, not a promise.
You need an autonomous multi-step agent. The two agents here propose once and stop.
You need performance figures or a service level. What scale means here is measured on stated machines and published with its environment, in the repository, never as a promise.