Skip to main content

bloomery

Entity-first spec compiler — declarative specs in, SQLMesh, dbt and Cube artifacts out, byte-for-byte the same every time.

PyPI Python Coverage OpenSSF Scorecard Licence

bloomery is a pure function library. You hand it declarative specs — a catalog, entities, mappings, metrics, marts, and optionally steps — and it returns SQLMesh, dbt and Cube artifacts, a MetricFlow manifest, and SQL for a metric request. It executes nothing and reads no warehouse.

Those specs carry what SQL cannot: grains, units, tax bases and additivity classes. That is the whole trick — the compiler refuses what a hand-written model would happily run, because it knows what the columns mean and not just what type they are.

What that buys is one claim, stated precisely because both ways of getting it wrong are easy: bloomery does not prove truth. It proves preservation of declared semantics. It refuses to emit a representation it cannot show preserves the grain, unit, tax basis and additivity you declared, and it refuses a query whose derivation it cannot construct. Whether the declarations are right about your business is a question it has no access to — what bloomery proves draws the whole boundary, including the six things it explicitly cannot establish.

Every request the planner answers comes back with that derivation attached: a target-independent semantic plan naming what was computed and the rule authorizing each step. It is evidence about the answer rather than the machinery producing it — the SQL is built alongside, not from it.

The number that looks right

Shipping is charged once per order. Someone flattens it into a mart at line grain, and SUM(shipping) overstates by the number of lines on each order. The SQL is valid, the join is correct, the tests pass, the dashboard renders — and finance finds it two quarters later. That class of bug survives syntax checks, type checks and code review, because nothing in the stack knows that shipping is an order-grain measure. bloomery does:

GuardrailError:
  1 error(s):
  - marts: marts.order_items.measures.shipping: measure 'shipping' has grain 'order'
    (one row per order), not the mart's grain 'order_item' (one row per line on an
    order) — measure grain must strictly equal mart grain (S-0027/D-2). Flattened
    into the mart it is duplicated once per 'order_item' row and any SUM over it
    overstates. Fix: remove it from this mart's measures, or serve it from a mart at
    grain 'order'

Not a warning. A compile error, with the spec path that caused it and the two ways out. The system may fail to answer a question; it may not answer it wrongly without saying so.

Quick start

uv add bloomery      # or: pip install bloomery

Python 3.12–3.14. No orchestrator, no cloud SDK, no database driver.

For an agent writing your specs, install the bloomery skill — specs, compiling, planning, quality rules, targets and the Python API, with every example checked against the release:

npx skills add morzecrew/bloomery
from bloomery import (
    LruManifestHydrator, 
    MetricFlowPlanner, 
    MetricRequest, 
    Target,
    build_project_ir, 
    compile_project, 
    load_catalog, 
    load_project,
)
from bloomery.naming import DefaultNaming

# The loaders take YAML *strings*, never paths: reading files is the caller's job.
catalog = load_catalog(catalog_yaml)
project = load_project({
    "entity_model.yaml": entities, 
    "mapping_orders.yaml": mapping,
    "metrics.yaml": metrics, 
    "marts.yaml": marts,
})

# Compile: specs in, a tuple of file-shaped artifacts out. Writing them is yours too.
for artifact in compile_project(
    project, 
    target=Target.SQLMESH, 
    dialect="duckdb",
    catalog=catalog,
):
    print(artifact.path)  # artifact.content is the model, audit or manifest

# The same specs serve queries. A request becomes SQL over a wide, pre-joined mart,
# planned by an embedded render-only MetricFlow and executed by nothing.
naming = DefaultNaming()
planner = MetricFlowPlanner(LruManifestHydrator(naming), naming=naming)

plan = planner.plan(
    build_project_ir(project, catalog=catalog),
    MetricRequest(metrics=("revenue",), dimensions=("ordered_month",)),
    dialect="duckdb",
)

print(plan.sql, plan.explanation.render())

That is examples/quickstart/run.py condensed — the full file, comments and filter parsing included, is run by the test suite on every commit (tests/unit/test_examples.py), so it cannot quietly rot.

The CLI is a thin argument shell over exactly these functions, and the only part of the package that touches a filesystem:

bloomery compile specs/ --target sqlmesh --dialect duckdb --out out/
bloomery resolve specs/          # what is computable, what is missing, what was refused
bloomery lineage specs/ --node metric.gross_revenue

A refusal exits 1 and a bad invocation exits 2, so a pipeline can tell "your spec is wrong" from "your command is wrong". Nothing is executed: bloomery run does not exist.

What bloomery does not do

  • It does not execute SQL. It emits artifacts and plans; SQLMesh, dbt or Cube run them.
  • It does no orchestration. Scheduling, backfills and deployment belong downstream.
  • It does not read your warehouse. Catalogs and profiles are inputs, computed elsewhere.
  • It contains no LLM. Proposals may be drafted with LLM assistance upstream, but they arrive as validated specs, and everything emitted — the human-readable query explanations included — is generated deterministically.
  • It has no clock and no randomness. Same specs in, byte-identical artifacts out, across machines, processes and PYTHONHASHSEED — enforced by test, not by intent.

Examples

Every project under examples/ runs, and a test covers each — the two pure ones end to end, the two container-backed ones at their compile step — so none can rot unnoticed. The seed data is deliberately not clean: padded emails, five spellings of one segment vocabulary, prices in integer cents, an unparseable timestamp.

Example Shows Infrastructure
quickstart/ The five core spec kinds; compile, then plan a metric request none
refusals/ Five specs that look right and cannot be right, with the real messages none
targets/ SQLMesh, dbt, Cube and the planner all actually running one container
lakehouse/ Iceberg via Lakekeeper: union merge, quality rules, quarantine, a blocking audit four containers
uv run python examples/quickstart/run.py     # no setup at all
cd examples/targets && just demo             # the interesting one

targets/ is worth the container. It compiles one spec set to SQLMesh and to dbt, builds both, and compares the two marts row for row — because "two frameworks, one spec, one answer" is a claim, and this turns it into a measurement.

Documentation

Full documentation: morzecrew.github.io/bloomery.

Stability

bloomery is 0.x, so a minor release may break the Python API — never quietly: every breaking change lands in CHANGELOG.md naming what moved and what to write instead. Pin the minor (bloomery>=0.2,<0.3).

Spec YAML is the stronger promise and does not wait for 1.0: a document that loads keeps loading, and a breaking grammar change mints a new <kind>_version. Emitted artifacts are explicitly not stable across versions — details.

Contributing

Contributions, issues and feature requests are welcome — see CONTRIBUTING.md, including the RFC process for larger changes.

Security

Please report security vulnerabilities privately as described in SECURITY.md.

Licence

MIT — see LICENSE.

Metadata

Release files for bloomery 0.11.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bloomery 0.11.0
File Size Uploaded Provenance Actions
bloomery-0.11.0.tar.gz 3.1 MB With provenance Details for bloomery-0.11.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for bloomery 0.11.0
File Interpreter ABI Platform Actions
bloomery-0.11.0-py3-none-any.whl Python 3 none any Details for bloomery-0.11.0-py3-none-any.whl

Total release size: 4.4 MB

Release files / bloomery-0.11.0.tar.gz

Download URL bloomery-0.11.0.tar.gz
Size 3.1 MB
Tags Source
SHA-256 checksum
How to use checksums
7cc064fd08262f3a44940379d4659430fad37f1884353639a8c768fabddd1bdd
BLAKE2b-256 checksum
How to use checksums
0027fda8d0824999015d49e70ba18f85fd1da8d7b548d9e07132083b43621888
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / bloomery-0.11.0-py3-none-any.whl

Download URL bloomery-0.11.0-py3-none-any.whl
Size 1.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
8e9d371a9107b7717af50864b917a5142039f52063824bcfe1a8b95dab475bc9
BLAKE2b-256 checksum
How to use checksums
fabb0ecf0bcc954e9e72e8be0cd31d1c34027a4c3eedbc58f70516a99c789196
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Security for bloomery 0.11.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for bloomery-0.11.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page