Getting Started
Try Semantic Rails with one command, create your own package, then connect an HTTP client or an agent. Every command uses the published package from PyPI, except the contributor steps marked "source checkout".
1. Try it, then install
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
To keep a semantic-rails command on your PATH, install it as a tool. If uv
warns that its tool directory isn't on your PATH, run uv tool update-shell
and open a new terminal.
uv tool install semantic-rails
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. With pip, run
python -m pip install semantic-rails inside a Python 3.11+ environment. On
Windows, activate the environment with .venv\Scripts\activate. Windows
isn't covered by our checks yet.
uv venv --python 3.12 source .venv/bin/activate uv pip install semantic-rails
git clone https://github.com/semantic-rails/semantic-rails.git cd semantic-rails uv sync --group dev
The source checkout includes the worked examples under examples/. From a
checkout, prefix commands with uv run.
2. Create your first 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
If you installed the command, drop uvx. 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.)
The interactive wizard, semantic-rails setup --interactive, walks through
the same steps. It can set a local profile and add the Query MCP and Architect MCP to
Claude Desktop or Codex. On POSIX it can also start a managed MCP HTTP server; on
Windows it uses client-launched stdio or a foreground HTTP terminal. Run it from an
installed semantic-rails, not through uvx: like
mcp setup, it writes the running Python's path into the client config.
This is the deterministic setup layer for a new project. It creates a split-layout package with starter data, examples, and package-local tests. Architect MCP can guide the same workflow from an MCP client, but the terminal path is always available.
The REPL is optional: semantic-rails repl --path ./my_package opens it.
It is useful for local authoring loops with repeated
ls, ask, run, debug, and
validate commands; agents and automation should use explicit CLI commands
or MCP tools. Type exit to quit the REPL.
Optional local defaults live in ~/.semantic_rails/profiles.yml. Run
semantic-rails profile init --package-path ./my_package when you want the
human CLI to use this package without repeating --path. Keep that file
local; it is not package source, deployment config, or cloud tenant config.
3. Optional bundled smoke package
These use the semantic-rails command installed in step 1. If you only use
uvx, put uvx in front of each one.
semantic-rails packages semantic-rails ask --package jaffle_shop "revenue by store" --run semantic-rails catalog --package jaffle_shop
jaffle_shop is a bundled synthetic fixture for smoke testing. It is not a
prerequisite for modeling your own data.
3b. Optional HTTP API and MCP server
PACKAGE_PATH="$(pwd)/my_package" semantic-rails mcp setup --path "$PACKAGE_PATH"
semantic-rails mcp setup --path "$PACKAGE_PATH" --client both --mcp query --install --yes
Use absolute paths for MCP client configuration because the client may not start in
your project directory. --mcp query installs the query server only;
--mcp both also installs 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. Install the command first. Copy-paste setup for Claude Code,
Codex, Cursor and the hosted demo is in the
Agent Quickstart.
For HTTP-capable MCP clients, run one foreground package server in a separate
terminal opened in the directory that holds my_package. It serves
the HTTP API and stateless Streamable HTTP at
http://127.0.0.1:8091/mcp; stop it with Ctrl-C.
PACKAGE_PATH="$(pwd)/my_package" semantic-rails serve --path "$PACKAGE_PATH" --host 127.0.0.1 --port 8091
curl -s http://127.0.0.1:8091/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-11-25' \
--data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| python -c 'import json, sys; tools=json.load(sys.stdin)["result"]["tools"]; print(f"{len(tools)} tools"); print("\n".join("- " + tool["name"] for tool in tools))'
When SEMANTIC_RAILS_API_KEYS or
SEMANTIC_RAILS_API_KEY_FILE is configured, /mcp requires
Authorization: Bearer ..., X-API-Key, or
X-Semantic-API-Key. Without configured keys, authentication is disabled
for local use; /health stays public. These headers are for the engine you
run yourself; Semantic Rails Cloud API keys use Authorization: ApiKey <key>
(see Connect assistants to Cloud). Caller policy context comes from
trusted transport headers rather than tool arguments. Install a trusted
policy-context resolver before exposing the server to callers with different
permissions.
semantic-rails serve --package jaffle_shop --host 127.0.0.1 --port 8081
Steps 4 and 5 use IDs from the bundled jaffle_shop package, so this serves
it. For your own package, use --path "$PACKAGE_PATH" and your package's
IDs.
semantic-rails serve and semantic-rails mcp stdio
are foreground server processes. Run them from a
separate terminal or let an MCP client launch stdio from its generated config.
Docker and ASGI make the runtime deployable, but this is not a hosted cloud bundle, managed acceleration layer, or full enterprise auth system.
4. Follow the guided builder path
The preferred public flow is no longer "write raw JSON first." Start with discovery, inspect the semantic object, then ask for the next legal move.
curl -s -X POST http://127.0.0.1:8081/api/v1/discover \
-H "Content-Type: application/json" \
-d '{
"terms": "revenue by store"
}'
curl -s -X POST http://127.0.0.1:8081/api/v1/build-options \
-H "Content-Type: application/json" \
-d '{
"query": {
"select": [{ "expression": "measure.jaffle.revenue_usd", "as": "revenue_usd" }]
},
"focus_terms": "revenue by store",
"focus_object_id": "measure.jaffle.revenue_usd",
"step": "group_by",
"limit": 6
}'
5. Run a first query
curl -s -X POST http://127.0.0.1:8081/api/v1/query \
-H "Content-Type: application/json" \
-d '{
"query": {
"select": ["measure.jaffle.revenue_usd"],
"group_by": ["dimension.jaffle_store_name"],
"time": {
"temporal_role": "temporal_role.jaffle_order_time",
"grain": "month"
},
"order_by": [{ "field": "revenue_usd", "direction": "desc" }],
"limit": 5
}
}'
Querying a package outside configs/semantic_rails/
query, compile, validate, and MCP all accept
--path <dir>. Use that form for a package created in your own project
folder:
semantic-rails query --path ./my_package --query-json '{
"select": ["metric.my_package.total_amount"],
"limit": 5
}' --verbosity minimal --sql-profile off
The compact flags keep first-run output focused on rows and row counts. Omit them when you want SQL, trace, and explain metadata.
6. Run the test suite (source checkout)
uv run pytest -q tests/semantic_rails
What to do next
- Model or extend a package in Package Authoring.
- Wire an MCP client or agent with Agent Quickstart.
- Look up exact field shapes in Authoring Reference.
- Understand planner behavior in Query Planner.
- Use the staged API path in Agent Actions.