Skip to main content

Varda

CI PyPI Python Docs

Dimensional modeling for LinkML.

Varda is a profile of LinkML: a small vocabulary that lets you say a class is a fact table, that a column is a semi-additive measure, that a dimension keeps history. It then checks those claims and generates from them.

A model annotated with Varda is still an ordinary LinkML schema. Every other LinkML tool — gen-pydantic, gen-owl, gen-json-schema — will read it happily and ignore what it does not understand.

FctSale:
  annotations:
    varda:role: fact
    varda:fact_type: transaction
    varda:grain: one row per product per line of a sales receipt
  attributes:
    customer_key:
      range: integer
      annotations:
        varda:role: foreign_key
        varda:references: DimCustomer
    net_amount:
      range: decimal
      annotations:
        varda:role: measure
        varda:additivity: additive
        varda:unit: EUR
$ varda check model.yaml
8 tables checked against 22 rules (varda 0.1.0): 0 errors, 0 warnings

$ varda generate model.yaml --out out/
wrote out/docs/model.md
wrote out/sql/mart.sql

Install

pip install varda

Python 3.11+. The only runtime dependency is linkml-runtime.

What it gives you

Eleven annotations. Five on tables — role, grain, fact_type, scd, physical_name. Six on columns — role, references, additivity, semi_additive_over, unit, physical_name. That is the whole core vocabulary, and it is deliberately the whole core vocabulary.

Twenty-two rules that catch the mistakes worth catching:

V001–V003 the annotations themselves — typos, bad enum values, unknown prefixes
V101–V113 structure — a fact without a grain, a foreign key pointing at a fact, a dimension with no natural key
V201–V206 measures — an unclassified measure, a semi-additive one that never says what it cannot cross

The V2xx family exists because additivity is where the expensive errors live. A structural mistake usually breaks a query. An additivity mistake returns a number that looks entirely reasonable and is wrong, to someone who will act on it.

Two generators, sql and docs, producing runnable DDL and a Markdown reference. Both are deterministic: no timestamps, no environment, same model in and same bytes out, so the output can be committed and diffed.

Extending it

Varda's core is small on purpose. Anything specific to how your organization works — cost centers, retention, data classification, ownership — goes in an extension under your own prefix.

The smallest useful extension needs no Python at all. Write a LinkML schema declaring your vocabulary, then a varda.toml:

[[extension]]
name = "acme"
prefix = "acme"
profile = "profiles/acme.yaml"

From then on acme:cost_center is a first-class annotation: checked for typos, its enum values enforced, and listed by varda ext. Misspell it and you get

ERROR V001  DimStore
        unknown table annotation 'acme:cost_center'; declare it in
        acme.yaml or fix the typo

Full documentation: https://mluttikh.github.io/varda/

An extension with code behind it adds rules and generators through varda.ext, and ships as an installable package advertising the varda.extensions entry point. See SPEC.md for the interface and tests/fixtures/acme_ext/ for a complete worked example.

One party, one namespace; extensions add, they never redefine. An extension may introduce annotations, enums and rules under its own prefix. It may not add a value to TableRole or change what semi_additive means — every generator dispatches exhaustively on those, and the registry refuses at load rather than warning.

Commands

varda check MODEL validate; --strict fails on warnings too
varda generate MODEL --out DIR write artifacts; fails closed
varda rules list every rule, -v for reasoning
varda ext describe active extensions and their vocabulary
varda importmap print the LinkML import map

Exit codes are part of the contract: 0 success, 1 the model or run failed, 2 the invocation was wrong.

Status

0.1.0 — alpha. The vocabulary and rule codes are stable enough to build on; rule codes will not be renumbered. Analytical functions, model diffing, lineage and the drift gate are deliberately not here yet — see SPEC.md for what is deferred and why.

Building the documentation

pip install -e ".[docs]"
mkdocs serve

Then open http://127.0.0.1:8000/varda/ — note the /varda/ path, which comes from site_url because this is a GitHub Pages project site rather than a user site. Plain http://127.0.0.1:8000/ redirects there.

The vocabulary, rules and command-line pages are generated from the package itself into a git-ignored docs/reference/, so they cannot drift from the code. mkdocs serve regenerates them on every rebuild and watches src/ as well as docs/ — edit a rule's docstring and the page updates.

To build the static site the way CI does:

python scripts/gen_reference.py
mkdocs build --strict

--strict turns a broken internal link into a failed build. The generator is a standalone script rather than a plugin, so the site also builds under Zensical and ProperDocs from the same mkdocs.yml — see docs/design.md for why that matters.

License

MIT for the code. The profile vocabulary in src/varda/profile/varda.yaml is CC0, so it can be reused anywhere without attribution — a vocabulary that constrains its own reuse is not much of a vocabulary.

Release files for varda 0.1.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 varda 0.1.0
File Size Uploaded
varda-0.1.0.tar.gz 45.9 kB Details

Built distribution (wheel)

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

Total release size: 83.5 kB

Release files / varda-0.1.0.tar.gz

Download URL varda-0.1.0.tar.gz
Size 45.9 kB
Tags Source
SHA-256 checksum
How to use checksums
61b42209353560ad16f67034bd865a70152528dabedde21d455b6d430a956749
BLAKE2b-256 checksum
How to use checksums
8350dc9c216994c48375065b06a7f4750f53d4f5c8c7584b1ba181cf2d5d87f0
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 Aug 22, 2026.

Transparency log

Release files / varda-0.1.0-py3-none-any.whl

Download URL varda-0.1.0-py3-none-any.whl
Size 37.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b8ec4fa5010e804e89d67bf2bbf0a1c5bf7329e25114a082d375f376c0f5c5e9
BLAKE2b-256 checksum
How to use checksums
68a99d8ff42f1af6b7a59382d68e3d3ede0f4fc1269a193704d302d3891e818b
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 Aug 22, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.0 This release

2 release files

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