Skip to main content

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/:

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

bloomery-0.1.0.tar.gz (980.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bloomery-0.1.0-py3-none-any.whl (406.1 kB view details)

Uploaded Python 3

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

Hashes for bloomery-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cff697e97b823d6bfe911adafefcbca0df86f5345e86e4550a4d193574967f05
MD5 4ccb0a4793553873383b9094e3e5f4d1
BLAKE2b-256 85c87843e2a9238ab954c430f0528f41cf51e04e42219bdfcbb7c26dbb4d3884

See more details on using hashes here.

Provenance

The following attestation bundles were made for bloomery-0.1.0.tar.gz:

Publisher: release.yaml on morzecrew/bloomery

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for bloomery-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ca6bba2a4e1a86feb9429460fa17dd4e292da678b926f41a32a4bd97675efa30
MD5 469d80cb847090dfeb742e5af32fa2d1
BLAKE2b-256 0e3b79cae07e4fffc34916e0fb854ed8bfd9e18152b06614d5cf13741a55425b

See more details on using hashes here.

Provenance

The following attestation bundles were made for bloomery-0.1.0-py3-none-any.whl:

Publisher: release.yaml on morzecrew/bloomery

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page