Semantic Rails
Semantic Rails is an open-source, agent-first semantic layer, licensed Apache-2.0. You define metrics, dimensions and join paths once, in YAML. Agents then discover those definitions, plan a query and run it as governed SQL through an MCP server, a CLI or an HTTP API, instead of writing joins and metric formulas by hand.
- Runs locally on DuckDB with no account or server. Optional connectors cover Snowflake, BigQuery, Databricks, Postgres, Athena, ClickHouse, MotherDuck and DuckLake.
- No telemetry and no update checks. The engine makes network connections only for what you configure; see Telemetry and network access.
- Beta. See Project status for what is supported and what isn't yet.
Try it in one command
You need uv. It fetches a compatible Python (3.11 or newer) if your system Python is older.
uvx semantic-rails ask --package jaffle_shop "revenue by store" --run
This plans the question against the bundled synthetic Jaffle Shop package, then validates, compiles and runs the plan on DuckDB. It prints how it interpreted the question, the rows and any warnings, then the Query IR. To try the same loop without installing anything, use the browser demo or the hosted MCP endpoint below.
Quickstart with your own package
uvx semantic-rails init my_package --yes
uvx semantic-rails project validate --path ./my_package
uvx semantic-rails ask --path ./my_package "total amount by event type" --run
init writes a runnable starter package (YAML models, metrics, examples, tests and
CSV data). Edit it to describe your own tables, then rerun project validate.
Pass --path on commands that use your own package, or run them inside the package
directory. Without either, and without a saved profile, commands stop with
no_package_selected and list the ways to choose a package; at an interactive terminal,
ask first offers the bundled sample package. (--package only names a bundled
package, such as jaffle_shop.) Releases before 0.3.0 don't stop: there, commands fall
back to the bundled jaffle_shop package and exit 0.
To keep a semantic-rails command on your PATH instead of running it through uvx:
uv tool install semantic-rails
If uv warns that its tool directory isn't on your PATH, run uv tool update-shell and
open a new terminal.
Or install it into a project environment. Pin the Python version: on a machine without
a uv-managed Python, a bare uv venv can pick up the system Python (3.9 on stock macOS,
3.10 on Ubuntu 22.04), and then the install fails.
uv venv --python 3.12
source .venv/bin/activate
uv pip install semantic-rails
With pip, run python -m pip install semantic-rails inside a Python 3.11+
environment. On Windows, activate the environment with .venv\Scripts\activate; see the
agent quickstart
for how MCP differs there. CI doesn't cover Windows yet.
The interactive wizard, semantic-rails setup --interactive, walks through the same
steps and can register the MCP server with Claude Desktop or Codex. Run it from an
installed semantic-rails, not through uvx, for the reason given under
Claude Desktop below.
Inside semantic-rails repl, type author to add models, dimensions, measures, metrics and
segments with previews and validation.
Connect your agent
MCP clients may start in another directory, so give the package's absolute path.
Claude Code
claude mcp add semantic-rails -- uvx semantic-rails mcp stdio --path "$PWD/my_package"
Codex CLI
codex mcp add semantic-rails -- uvx semantic-rails mcp stdio --path "$PWD/my_package"
Claude Desktop. Install the command, then let Semantic Rails write the client config:
uv tool install semantic-rails
"$(uv tool dir --bin)/semantic-rails" mcp setup --path "$PWD/my_package" --client claude --mcp query --install --yes
uv tool dir --bin finds the command even when uv's tool directory isn't on your
PATH yet. Run mcp setup without --install --yes to preview the change.
--client codex and --client both also work, and --mcp both adds the Architect
MCP, which can edit package files. Don't run mcp setup --install through uvx: the
config would point into uv's cache, which uv cache clean deletes.
Cursor. Install the command and print the two absolute paths the config needs:
uv tool install semantic-rails
echo "$(uv tool dir --bin)/semantic-rails"
echo "$PWD/my_package"
Then add the server to .cursor/mcp.json:
{
"mcpServers": {
"semantic-rails": {
"command": "/absolute/path/to/semantic-rails",
"args": ["mcp", "stdio", "--path", "/absolute/path/to/my_package"]
}
}
}
Hosted demo (no install). https://semantic-rails.com/mcp is a public Streamable
HTTP endpoint over the same synthetic Jaffle Shop data. It is anonymous and
rate-limited, and it can't load your package.
claude mcp add --transport http semantic-rails-demo https://semantic-rails.com/mcp
codex mcp add semantic-rails-demo --url https://semantic-rails.com/mcp
The agent loop, tool policy and HTTP routes are in
docs/AGENT_QUICKSTART.md.
The full MCP contract, including its interface versions and semantic-rails mcp http
for a local Streamable HTTP server, is in
docs/MCP_INTERFACE.md.
How it works
An agent works through separate, inspectable steps instead of one SQL string:
discover -> plan -> execute
discovermaps business terms to governed metric, dimension and segment IDs.inspectopens one object's card when the agent needs its aggregations, values or time roles.plandrafts Query IR from a natural-language question and checks the draft against the question. Run the draft when its status isokand it has no warnings; otherwise the response says what the draft misses.build-optionsandvalid-valuesguide step-by-step builders instead.execute(the CLI'squery, HTTP/api/v1/query) validates, compiles and runs the Query IR where the package's connection lives. It rejects unknown fields, dimension mismatches, bad filters and policy failures with structured errors and, where possible, recovery hints.validateandcompileare optional dry runs of the same checks.validatereturns the diagnostics without running anything;compilealso renders SQL for the target warehouse. Atcompactverbosity (the CLI's default) orfull,compilereturns anexplainpayload: the chosen join path to each entity, the candidate paths it considered and the relationship contracts along the chosen path. The MCP tool defaults tominimal, which leavesexplainout.
The engine design is in docs/ARCHITECTURE.md, and the supported modeling surface is in docs/CAPABILITIES.md.
How it compares
dbt's Semantic Layer (MetricFlow), Cube, LookML and Malloy are more mature, and they reach warehouses Semantic Rails doesn't support yet: Cube alone connects to Redshift, SQL Server, Microsoft Fabric, MySQL and Trino. dbt, Cube and Looker also connect to far more BI tools and offer caching or pre-aggregation. Semantic Rails is narrower: an engine built around the agent loop above, which you can run locally or embed.
The comparison pack asks the same 16 questions of six modeled layers: Semantic Rails, MetricFlow, Cube, Malloy, Snowflake Semantic Views and KtX. It compares capability, not performance; its support labels describe the authored models, not each layer's limits. Nine questions were chosen to exercise primitives Semantic Rails ships. The output consistency check compares five layers on the current shared dataset, including Semantic Rails, against an independent SQL answer key: all 16 match. Cube's captured SQL was replayed on current data, but Cube itself was not rerun. Snowflake Semantic Views is a stale capture on an older dataset and is excluded from that count; it matches 14 questions and differs on q07 and q16. The authored models and shared data leave some intended semantics weakly tested, so matching outputs are not a ranking.
Coming from MetricFlow? Translate a MetricFlow YAML directory or a dbt
semantic_manifest.json into a new package. The importer is partial: models it can't
translate are listed as warnings, but metrics that depended on them can still be
written out and then fail to compile. Compile the metrics you rely on before trusting
the import.
uvx semantic-rails import --from metricflow --source target/semantic_manifest.json \
--output . --package-id my_dbt_package
The imported package targets DuckDB and names a seed script,
data/seed_my_dbt_package.sql, that the import doesn't create. Before
project validate, replace seed with your warehouse's connection (see
package.yml)
or add that script.
Warehouses
DuckDB is included. Add a connector only when you need it, for example Postgres:
uv tool install 'semantic-rails[postgres]'
The other connector extras are snowflake, bigquery, databricks, athena and
clickhouse, and all installs every connector. In a project environment, use
uv pip install 'semantic-rails[all]'. MotherDuck and DuckLake use the core duckdb
dependency. Keep secrets in environment
variables or files, not in package YAML. See
docs/DEPLOYMENT.md and
docs/ADDING_A_DIALECT.md.
Telemetry and network access
Semantic Rails collects no telemetry and has no update check. The engine opens network connections only to:
- the warehouses configured in your package's
connectionblock; - DuckDB's extension repository (extensions.duckdb.org): DuckDB downloads an extension it doesn't bundle the first time a query needs one, for example for MotherDuck, DuckLake or remote files;
- its own local MCP server, when
semantic-rails mcp startormcp statuschecks that server's/healthendpoint.
The hosted demo at semantic-rails.com is a separate deployment with its own privacy notice.
Project status
Semantic Rails is beta software. The supported core is the open-source runtime, the
CLI, the MCP stdio and HTTP servers, the /api/v1/* HTTP API, the DuckDB path and
Snowflake execution. The other connectors are supported with guardrails, and live
warehouse credentials are exercised on demand, not in every CI run. The
agent quickstart
lists what is experimental or out of scope.
Known limitations in the current release:
planreports the parts of a question its draft doesn't honor, aslow_confidenceor aPLAN_UNMATCHED_TERMSwarning, but its checks don't cover every phrasing. For "revenue by store before today" it plans today alone and reportsokwith only that warning, andaskruns it. Check the Query IR, orask's "Interpreted as" line, before you rely on the numbers.askrounds its tables, but JSON results (query,ask --json, MCPexecuteand the HTTP API) return the warehouse's floating-point values as they are, for example486468.17999985756for a currency total.- The MetricFlow importer is partial. It can keep a metric whose model it dropped, and that metric then fails to compile.
Roadmap
Work in progress, without dates:
- Query MCP interface v2 as the default, once it answers a held-out question set at least as accurately as v1. In 0.3.0 it is opt-in.
- One-step agent setup: Claude Code and Codex plugins and a Claude Desktop bundle.
- A flagship example: a dbt project on an open dataset, modeled end to end.
- Broader native-model coverage in the comparison pack and a refreshed Snowflake capture on the current dataset.
- Import and export for Apache Ossie, the incubating Open Semantic Interchange specification.
Questions and proposals are welcome in GitHub Discussions.
Docs
- Getting started
- Agent quickstart
- Package authoring
- MCP interface
- Architect MCP
- Query API
- Capabilities
- Architecture
- Benchmark evidence
- Deployment
- Comparison pack
- Changelog
Contributing
CONTRIBUTING.md covers scope, architecture ownership and the validation commands. To work from a source checkout:
git clone https://github.com/semantic-rails/semantic-rails.git
cd semantic-rails
uv sync --group dev
uv run semantic-rails packages
uv run semantic-rails query --package jaffle_shop --query-json '@examples/jaffle_shop_revenue_by_store.json' --verbosity minimal --sql-profile off
Expected package output includes the bundled synthetic fixture:
jaffle_shop
Contributor release smoke for the bundled package:
uv run semantic-rails parse-config --path configs/semantic_rails/jaffle_shop
uv run semantic-rails validate-config --path configs/semantic_rails/jaffle_shop --quiet
Build and verify the exact wheel and sdist before publishing:
uv build --out-dir dist
uv pip install --python .venv/bin/python --reinstall dist/semantic_rails-0.3.0-py3-none-any.whl
uv run python scripts/verify_package_distribution.py --dist-dir dist --no-build
Package naming
Semantic Rails is the public product name. The PyPI distribution is
semantic-rails, the Python import package is semantic_rails, and the CLI is
semantic-rails. The published distribution also includes mf2sr, the
MetricFlow translator behind semantic-rails import.
Support, security and license
Support, issue reporting, conduct and security reporting are documented in SUPPORT.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md and SECURITY.md.
Semantic Rails is licensed under Apache 2.0; see LICENSE. Everything in this repository is open source, with no gated features. Semantic Rails, Inc., which runs semantic-rails.com, also offers a hosted service; nothing here requires it.
Release files for semantic-rails 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| semantic_rails-0.3.0.tar.gz | 7.1 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| semantic_rails-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.4 MB
Release files / semantic_rails-0.3.0.tar.gz
| Download URL | semantic_rails-0.3.0.tar.gz |
|---|---|
| Size | 7.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0701b4fd2aa98affa9ae1e21fe6d8d96e06b8fb541914494d0545e9591553eec
|
|
BLAKE2b-256 checksum How to use checksums |
f8e8543bced753ca816082790ddf7b98f4480e117726acf5baa5967a58d4ad97
|
| 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 Sep 25, 2026.
Transparency logRelease files / semantic_rails-0.3.0-py3-none-any.whl
| Download URL | semantic_rails-0.3.0-py3-none-any.whl |
|---|---|
| Size | 7.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
36f35009694de7802fbefe8f0abf0352b94446d19fd94fa5da36c4dbf8819b45
|
|
BLAKE2b-256 checksum How to use checksums |
810c313672efe6a5a4307b542098bb47e23a1c149d202664beed848c8d318eca
|
| 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 Sep 25, 2026.
Transparency log