bloomery
Entity-first spec compiler: declarative entity/mapping/metric specs, compiled deterministically into SQLMesh, dbt, and Cube artifacts.
What it is
bloomery is a pure function library. You hand it declarative specs — a catalog, entities,
mappings, metrics, marts, and optionally steps — and it compiles them into ready-to-run
artifacts for SQLMesh, dbt, and Cube: models, audits, and semantic-layer definitions.
The same specs also serve metric queries at request time: a structured MetricRequest
becomes SQL over a wide mart, planned by an embedded, render-only MetricFlow.
- Deterministic — same specs in, byte-identical artifacts out, across machines, processes, and hash seeds. No clocks, no randomness, no environment reads.
- Fail-closed guardrails — grain fan-out, additivity violations, and contract breaks are compile errors with named reasons, not silent wrong numbers downstream.
- Reviewable — emitted artifacts are stable-sorted, pretty-printed text, so a diff of the output is a faithful diff of the semantic change.
What it is not
- It does not execute SQL — it emits artifacts and plans for engines and frameworks that do.
- It does no orchestration — scheduling, backfills, and deployment belong to SQLMesh, dbt, or whatever runs the artifacts.
- It contains no LLM — specs are authored by people (or by tools upstream of this library); compilation is deterministic all the way down.
Quick start
uv add bloomery
Compile specs into SQLMesh artifacts (the library never touches the filesystem — writing is your loop):
from bloomery import Target, compile_project, load_catalog, load_project
catalog = load_catalog(catalog_yaml)
project = load_project(
{
"entity_model.yaml": entities_yaml,
"mapping_orders.yaml": mapping_yaml,
"metrics.yaml": metrics_yaml,
"marts.yaml": marts_yaml,
}
)
artifacts = compile_project(project, target=Target.SQLMESH, dialect="duckdb", catalog=catalog)
for artifact in artifacts:
print(artifact.path) # write artifact.content wherever your repo keeps models
Or from a shell — 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 schema --out schemas/ # JSON Schema per spec kind, for editors and validators
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.
Assess a spec before it compiles — refusals come back as a value, alongside whatever analysis completed before them, so a draft mid-edit still reports what it would give you:
from bloomery import Stage, evaluate
evidence = evaluate(project, catalog=catalog)
evidence.stage_reached # read this first: at any stage but COMPLETE the rest is a prefix
evidence.reachable # ('gross_revenue', 'order_count', …)
evidence.unreachable # margin, blocked on 'cogs' — the specific leaf, not a summary
evidence.refusals # each with its own source path into the spec that caused it
Plan a metric request over the mart those specs declared — SQL out, nothing executed:
from bloomery import LruManifestHydrator, MetricFlowPlanner, MetricRequest, build_project_ir
from bloomery.naming import DefaultNaming
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)
print(plan.explanation.render())
Filters are typed CNF clauses (Predicate / AnyOf — implicit AND, one level of OR), and
bloomery.planner.parse_filter_json is a public front door for the Mongo-flavoured JSON
grammar ($and/$or/$not, field maps): it normalizes (De Morgan → complement inversion
→ capped CNF) before refusing, and refuses only from the closed, drift-guarded list
exported as bloomery.planner.KNOWN_UNSUPPORTED:
from bloomery.planner import parse_filter_json
filters = parse_filter_json(
{
"customer_id": {"$neq": "internal"},
"$or": [{"ordered_month": {"$gte": "2024-01-01"}}, {"ordered_month": "2023-12-01"}],
}
) # → (Predicate(…), AnyOf(…)) — pass straight to MetricRequest(filters=…)
The runnable version of both snippets lives in
examples/quickstart/:
uv run python examples/quickstart/run.py
Status
0.1.0 — the first release. Everything the library does ships behind the quality gate: the spec layer over six document kinds, the deterministic IR, transforms and typecheck, resolution, fail-closed guardrails, declarative data quality with quarantine and replay, steps as referenced implementations, wide marts with role-playing dates, the SQLMesh/dbt/Cube emitters over DuckDB/Trino/Postgres, the MetricFlow-backed planner with manifest hydration, spec-diff planning, spec assessment, the CLI and the JSON Schema export. Every test tier runs, including the Docker-backed engine matrix, the target e2e tiers and the three-way equivalence tier.
From this release the promises in Stability bind: per-kind versioning over spec YAML (fully), SemVer over the Python API (breaking changes are allowed in a minor below 1.0, but never silent), and emitted artifacts explicitly not stable across versions — byte-reproducible for fixed inputs, which is determinism rather than a cross-version promise. Pin the minor if you want the API to hold still.
Designs that have not yet landed live as RFCs in rfcs/; code that
contradicts a live RFC is the bug, not the RFC. An RFC is retired once it ships — the
code, the tests and the documentation are the account of what bloomery already does.
Documentation
Full documentation is available at https://morzecrew.github.io/bloomery/:
- Quickstart — specs to compiled artifacts to a planned query.
- Concepts — the domain model, the compile pipeline, determinism, guardrails, wide marts.
- How-to guides — emit SQLMesh, Cube, or dbt; plan a metric request; evolve a spec safely.
- Reference — spec schemas, transforms, errors, API, stability.
Contributing
Contributions, issues, and feature requests are welcome. See CONTRIBUTING.md for details — including the RFC process for larger changes.
Licence
bloomery is licensed under the MIT License — see LICENSE for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bloomery-0.1.0.tar.gz.
File metadata
- Download URL: bloomery-0.1.0.tar.gz
- Upload date:
- Size: 980.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cff697e97b823d6bfe911adafefcbca0df86f5345e86e4550a4d193574967f05
|
|
| MD5 |
4ccb0a4793553873383b9094e3e5f4d1
|
|
| BLAKE2b-256 |
85c87843e2a9238ab954c430f0528f41cf51e04e42219bdfcbb7c26dbb4d3884
|
Provenance
The following attestation bundles were made for bloomery-0.1.0.tar.gz:
Publisher:
release.yaml on morzecrew/bloomery
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bloomery-0.1.0.tar.gz -
Subject digest:
cff697e97b823d6bfe911adafefcbca0df86f5345e86e4550a4d193574967f05 - Sigstore transparency entry: 2478275044
- Sigstore integration time:
-
Permalink:
morzecrew/bloomery@e7f71a4028b361e02d7143a22db11548cf5a7f1c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/morzecrew
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@e7f71a4028b361e02d7143a22db11548cf5a7f1c -
Trigger Event:
push
-
Statement type:
File details
Details for the file bloomery-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bloomery-0.1.0-py3-none-any.whl
- Upload date:
- Size: 406.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca6bba2a4e1a86feb9429460fa17dd4e292da678b926f41a32a4bd97675efa30
|
|
| MD5 |
469d80cb847090dfeb742e5af32fa2d1
|
|
| BLAKE2b-256 |
0e3b79cae07e4fffc34916e0fb854ed8bfd9e18152b06614d5cf13741a55425b
|
Provenance
The following attestation bundles were made for bloomery-0.1.0-py3-none-any.whl:
Publisher:
release.yaml on morzecrew/bloomery
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bloomery-0.1.0-py3-none-any.whl -
Subject digest:
ca6bba2a4e1a86feb9429460fa17dd4e292da678b926f41a32a4bd97675efa30 - Sigstore transparency entry: 2478275116
- Sigstore integration time:
-
Permalink:
morzecrew/bloomery@e7f71a4028b361e02d7143a22db11548cf5a7f1c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/morzecrew
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yaml@e7f71a4028b361e02d7143a22db11548cf5a7f1c -
Trigger Event:
push
-
Statement type: