{"id":48552304,"url":"https://github.com/motleyai/slayer","last_synced_at":"2026-05-04T11:03:26.367Z","repository":{"id":345486026,"uuid":"1184045599","full_name":"MotleyAI/slayer","owner":"MotleyAI","description":"SLayer: a lightweight open-source semantic layer for AI agents and humans","archived":false,"fork":false,"pushed_at":"2026-04-06T08:09:44.000Z","size":3244,"stargazers_count":21,"open_issues_count":3,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-06T10:19:49.578Z","etag":null,"topics":["semantic-layer"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/motley-slayer/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MotleyAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-17T07:40:08.000Z","updated_at":"2026-04-06T08:09:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/MotleyAI/slayer","commit_stats":null,"previous_names":["motleyai/slayer"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/MotleyAI/slayer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MotleyAI%2Fslayer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MotleyAI%2Fslayer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MotleyAI%2Fslayer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MotleyAI%2Fslayer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MotleyAI","download_url":"https://codeload.github.com/MotleyAI/slayer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MotleyAI%2Fslayer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31547845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["semantic-layer"],"created_at":"2026-04-08T09:01:54.296Z","updated_at":"2026-05-04T11:03:26.360Z","avatar_url":"https://github.com/MotleyAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/MotleyAI/slayer/main/docs/images/slayer-hero.png\" alt=\"SLayer — AI agent operating a semantic layer\" width=\"600\"\u003e\n\u003c/p\u003e\n\n[![PyPI](https://img.shields.io/pypi/v/motley-slayer?label=PyPI)](https://pypi.org/project/motley-slayer/)\n[![Python](https://img.shields.io/pypi/pyversions/motley-slayer)](https://pypi.org/project/motley-slayer/)\n[![Docs](https://img.shields.io/badge/docs-readthedocs-blue)](https://motley-slayer.readthedocs.io/)\n[![License](https://img.shields.io/github/license/MotleyAI/slayer)](LICENSE)\n[![GitHub stars](https://img.shields.io/github/stars/MotleyAI/slayer?style=social)](https://github.com/MotleyAI/slayer/stargazers)\n\n**SLayer** is a semantic layer that lets AI agents query your database correctly.\n\n\u003e If you find SLayer useful, a ⭐ helps others discover it!\n\n---\n\n## How it works\n\nSLayer sits between your database and whatever consumes the data – AI agents, internal tools, dashboards, or scripts. You define your data models (or let SLayer auto-generate them from the schema), and query using a [structured API](https://motley-slayer.readthedocs.io/en/latest/concepts/queries/) of measures, dimensions, and filters instead of writing SQL directly.\n\nSLayer compiles these queries into the correct SQL for your database, handling joins, aggregations, time-based calculations, and dialect differences so that consumers don't have to.\n\n### SLayer is\n\n1. **dynamic**: models can be updated at any time and used immediately; aggregations are [defined in queries, not models](https://motley-slayer.readthedocs.io/en/latest/examples/07_aggregations/aggregations/)\n2. **simple**: query structure is intuitive and easily understood by LLMs and humans\n3. **expressive**: [supports](https://motley-slayer.readthedocs.io/en/latest/examples/04_time/time/) queries like _\"month-on-month % increase in total revenue, compared to the previous year\"_\n4. **embeddable**: can be used as a standalone service or imported as a Python module with no extra server\n5. **flexible**: exposes [MCP](https://github.com/MotleyAI/slayer?tab=readme-ov-file#mcp-server), [REST API](https://github.com/MotleyAI/slayer?tab=readme-ov-file#rest-api), [CLI](https://github.com/MotleyAI/slayer?tab=readme-ov-file#cli) and [Python](https://github.com/MotleyAI/slayer?tab=readme-ov-file#python-client) interfaces; [supports](https://motley-slayer.readthedocs.io/en/latest/configuration/datasources/#supported-database-types) most popular databases\n\nSee also: [automatic model ingestion](https://motley-slayer.readthedocs.io/en/latest/concepts/ingestion/), [queries-as-models](https://motley-slayer.readthedocs.io/en/latest/examples/06_multistage_queries/multistage_queries/), [auto-applied filters](https://motley-slayer.readthedocs.io/en/latest/concepts/models/#model-filters), and [more](https://motley-slayer.readthedocs.io/en/latest/).\n\n\u003e Why not just let agents write SQL? Because they get it wrong often enough to matter – see our [blog post](https://motley.ai/blog-posts/why-generating-raw-sql-by-agents-is-hard) and dbt's [benchmark analysis](https://docs.getdbt.com/blog/semantic-layer-vs-text-to-sql-2026?version=1.12).\n\n## Quickstart\n\nWe recommend using [uv](https://docs.astral.sh/uv/), especially if you don't work in a Python project.\n\nTo run the server:\n\n```bash\n# Instant demo — spins up the bundled Jaffle Shop DuckDB and ingests it\nuvx --from 'motley-slayer[all]' slayer serve --demo\n\n# Or run without --demo and connect your own data afterwards\nuvx --from 'motley-slayer[all]' slayer serve\n```\n\nOr to add the MCP server:\n\n```bash\n# With the Jaffle Shop demo preloaded (zero-config quickstart)\nclaude mcp add slayer -- uvx --from 'motley-slayer[all]' slayer mcp --demo\n\n# Or without the demo\nclaude mcp add slayer -- uvx --from 'motley-slayer[all]' slayer mcp\n```\n\nThe `--demo` flag additionally requires [`jafgen`](https://github.com/rossbowen/jaffle-shop-generator) — install hints are printed if it's missing.\n\nThen [configure a datasource](https://github.com/MotleyAI/slayer?tab=readme-ov-file#datasource-setup) or ask your agent to help you do it.\n\nRead more on how to get started with [MCP](https://motley-slayer.readthedocs.io/en/latest/getting-started/mcp/), [CLI](https://motley-slayer.readthedocs.io/en/latest/getting-started/cli/), [REST API](https://motley-slayer.readthedocs.io/en/latest/getting-started/rest-api/), [Python](https://motley-slayer.readthedocs.io/en/latest/getting-started/python/) in the docs.\n\n## Interfaces\n\n### REST API\n\n```bash\n# Query\ncurl -X POST http://localhost:5143/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"source_model\": \"orders\", \"measures\": [\"*:count\"], \"dimensions\": [\"status\"]}'\n\n# List models (returns name + description)\ncurl http://localhost:5143/models\n\n# Get a single datasource (credentials masked)\ncurl http://localhost:5143/datasources/my_postgres\n```\n\nSee more in the [docs](https://motley-slayer.readthedocs.io/en/latest/reference/rest-api/).\n\n### MCP Server\n\nSLayer supports two MCP transports, **HTTP** (served alongside the API) and **stdio** (serverless, spawned by the agent).\n\n```bash\n# 1. stdio-based, does not require a running server\nclaude mcp add slayer -- slayer mcp\n\n# 1b. same, but preload the Jaffle Shop demo on startup\nclaude mcp add slayer -- slayer mcp --demo\n\n# 2. HTTP-based (SSE), provided SLayer server is already running\nclaude mcp add slayer-remote --transport sse --url http://localhost:5143/mcp/sse\n```\n\nSLayer **does not expose credentials** to consumers once created.\n\nBoth transports expose the same tools, allowing to inspect, create and update datasources and models and run queries. More info in the [docs](https://motley-slayer.readthedocs.io/en/latest/reference/mcp/).\n\n### Python Client\n\nUseful for agents working in code execution environments, e.g. for AI data analytics, as well as any Python apps.\n\n```python\nfrom slayer.client.slayer_client import SlayerClient\nfrom slayer.core.query import SlayerQuery\n\n# Remote mode (connects to running server)\nclient = SlayerClient(url=\"http://localhost:5143\")\n\n# Or local mode (no server needed)\nfrom slayer.storage.yaml_storage import YAMLStorage\nclient = SlayerClient(storage=YAMLStorage(base_dir=\"./my_models\"))\n\n# Query data\nquery = SlayerQuery(\n    source_model=\"orders\",\n    measures=[\"*:count\", \"revenue:sum\"],\n    dimensions=[\"status\"],\n    limit=10,\n)\ndf = client.query_df(query)\nprint(df)\n```\n\n### CLI\n\n```bash\n# Run a query directly from the terminal\nslayer query '{\"source_model\": \"orders\", \"measures\": [\"*:count\"], \"dimensions\": [\"status\"]}'\n\n# Or from a file\nslayer query @query.json --format json\n```\n\nThese commands do not depend on a running server.\n\n## Models\n\nBy default, models are defined as YAML files. Add an optional `description` to help users and agents understand complex models:\n\n```yaml\nname: orders\nsql_table: public.orders\ndata_source: my_postgres\ndescription: \"Core orders table with revenue metrics\"\n\n# A single `columns` list — every column can be used as a group-by key\n# OR as the input to a query-time aggregation, gated by type/PK rules.\ncolumns:\n  - name: id\n    sql: id\n    type: number\n    primary_key: true\n  - name: status\n    sql: status\n    type: string\n  - name: created_at\n    sql: created_at\n    type: time\n  - name: revenue\n    sql: amount\n    type: number\n  - name: quantity\n    sql: qty\n    type: number\n\n# Optional library of named formulas that queries can reference by bare name.\nmeasures:\n  - name: aov\n    formula: \"revenue:sum / *:count\"\n    label: \"Average Order Value\"\n```\n\n## Measures\n\nThe `measures` parameter on a query specifies what data columns to return. Aggregations are picked at query time via colon syntax (`revenue:sum`, `*:count`); transforms wrap them (`cumsum(revenue:sum)`).\n\n```json\n{\n  \"source_model\": \"orders\",\n  \"dimensions\": [\"status\"],\n  \"time_dimensions\": [{\"dimension\": \"created_at\", \"granularity\": \"month\"}],\n  \"measures\": [\n    \"*:count\",\n    \"revenue:sum\",\n    {\"formula\": \"revenue:sum / *:count\", \"name\": \"aov\", \"label\": \"Average Order Value\"},\n    \"cumsum(revenue:sum)\",\n    \"change_pct(revenue:sum)\",\n    {\"formula\": \"last(revenue:sum)\", \"name\": \"latest_rev\"},\n    {\"formula\": \"time_shift(revenue:sum, -1, 'year')\", \"name\": \"rev_last_year\"},\n    {\"formula\": \"time_shift(revenue:sum, -2)\", \"name\": \"rev_2_periods_ago\"},\n    {\"formula\": \"lag(revenue:sum, 1)\", \"name\": \"rev_prev_row\"},\n    \"rank(revenue:sum)\",\n    {\"formula\": \"change(cumsum(revenue:sum))\", \"name\": \"cumsum_delta\"}\n  ]\n}\n```\n\nAvailable functions: `cumsum`, `time_shift`, `change`, `lag`, and more – see [docs](https://motley-slayer.readthedocs.io/en/latest/concepts/formulas/). Formulas support arbitrary nesting — e.g., `change(cumsum(revenue:sum))` or `cumsum(revenue:sum) / *:count`.\n\n## Filters\n\nFilters use simple formula strings — no verbose JSON objects:\n\n```json\n{\n  \"source_model\": \"orders\",\n  \"measures\": [\"*:count\", \"revenue:sum\"],\n  \"filters\": [\n    \"status == 'completed'\",\n    \"amount \u003e 100\"\n  ]\n}\n```\n\nFilters support a variety of operators, composition, pattern matching. Transforms \u0026 computed columns can also be used for filtering. See [docs](https://motley-slayer.readthedocs.io/en/latest/concepts/queries/#filters) for more.\n\n## Auto-Ingestion\n\nConnect to a database and generate models automatically. SLayer introspects the schema, detects foreign key relationships, and creates models with explicit join metadata.\n\nFor example, given tables `orders → customers → regions` (via FKs), the `orders` model will automatically include:\n\n- Joined dimensions: `customers.name`, `regions.name`, etc. (dotted syntax)\n- Count-distinct measures: `customers.*:count_distinct`, `regions.*:count_distinct`\n- Explicit joins — LEFT JOINs are constructed dynamically at query time\n\n```bash\n# Via CLI\nslayer ingest --datasource my_postgres --schema public\n\n# Via API\ncurl -X POST http://localhost:5143/ingest \\\n  -d '{\"datasource\": \"my_postgres\", \"schema_name\": \"public\"}'\n```\n\nVia MCP, agents can do this conversationally:\n\n1. `create_datasource(name=\"mydb\", type=\"postgres\", host=\"localhost\", database=\"app\", username=\"user\", password=\"pass\")`\n2. `ingest_datasource_models(datasource_name=\"mydb\", schema_name=\"public\")`\n3. `models_summary(datasource_name=\"mydb\")` → `inspect_model(model_name=\"orders\")` → `query(...)`\n\n## Datasource Setup\n\nThe fastest way is from the CLI — pass a connection URL and optionally ingest models in one step:\n\n```bash\nslayer datasources create postgresql://user:${DB_PASSWORD}@localhost/analytics --ingest\n```\n\nOr configure datasources as individual YAML files in the `datasources/` directory:\n\n```yaml\n# datasources/my_postgres.yaml\nname: my_postgres\ntype: postgres\nhost: ${DB_HOST}\nport: 5432\ndatabase: ${DB_NAME}\nusername: ${DB_USER}\npassword: ${DB_PASSWORD}\n```\n\nEnvironment variable references (`${VAR}`) are resolved at read time.\n\nSee more in the [docs](https://motley-slayer.readthedocs.io/en/latest/configuration/datasources/).\n\n## Storage Backends\n\nSLayer ships with two storage backends:\n\n- **YAMLStorage** (default) — models and datasources as YAML files on disk. Great for version control.\n- **SQLiteStorage** — everything in a single SQLite file. Good for embedded use or when you don't want to manage files.\n\nSLayer allows easily implementing your own storage backends, which is useful for features such as tenant isolation.\n\nSee the [documentation page for storage backends](https://motley-slayer.readthedocs.io/en/latest/configuration/storage/) for more.\n\n## Roadmap\n\n|   #   | Step                                            | Status |\n| :---: | ----------------------------------------------- | :----: |\n|   1   | Dynamic joins                                   |   ✅    |\n|   2   | Multi-stage queries                             |   ✅    |\n|   3   | Cross-model measures                            |   ✅    |\n|   4   | Aggregation at query time                       |   ✅    |\n|   5   | Smart output formatting (currency, percentages) |   ✅    |\n|   6   | Unpivoting                                      |   ❌    |\n|   7   | Auto-propagating filters                        |   ❌    |\n|   8   | Asof joins                                      |   ❌    |\n|   9   | Chart generation (eCharts)                      |   ❌    |\n\n## Examples\n\nThe `examples/` directory contains runnable examples that also serve as integration tests:\n\n| Example                            | Description                               |\n| ---------------------------------- | ----------------------------------------- |\n| [embedded](examples/embedded/)     | SQLite, no server needed                  |\n| [postgres](examples/postgres/)     | Docker Compose with Postgres + REST API   |\n| [mysql](examples/mysql/)           | Docker Compose with MySQL + REST API      |\n| [clickhouse](examples/clickhouse/) | Docker Compose with ClickHouse + REST API |\n\n## Tutorials\n\nThe `docs/examples/` directory contains Jupyter notebooks that walk through SLayer's features step by step.\n\n| Notebook                                                   | Topic                                                                                    |\n| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------- |\n| [SQL vs DSL](docs/examples/02_sql_vs_dsl/)                 | How model SQL and query DSL stay cleanly separated                                       |\n| [Auto-Ingestion](docs/examples/03_auto_ingest/)            | Schema introspection, FK graph discovery, automatic model generation                     |\n| [Time Operations](docs/examples/04_time/)                  | `change`, `change_pct`, `time_shift`, `lag`, `lead`, `last` — composable time transforms |\n| [Joins](docs/examples/05_joins/)                           | Dot syntax, multi-hop dimensions, diamond join disambiguation                            |\n| [Joined Measures](docs/examples/05_joined_measures/)       | Cross-model measures with sub-query isolation                                            |\n| [Multistage Queries](docs/examples/06_multistage_queries/) | Query chaining, queries-as-models, `ModelExtension`                                      |\n\n## Claude Code Skills\n\nSLayer includes Claude Code skills in `.claude/skills/` to help Claude understand the codebase:\n\n- **slayer-overview** — architecture, package structure, MCP tools list\n- **slayer-query** — how to construct queries with measures, dimensions, filters, time dimensions\n- **slayer-models** — model definitions, datasource configs, auto-ingestion, incremental editing\n\n## Known limitations\n\nSLayer currently has no caching or pre-aggregation engine.\nIf you need to process lots of requests to large databases at sub-second latency, consider adding a caching layer or pre-aggregation engine.\n\n## License\n\nMIT — see [LICENSE](https://github.com/MotleyAI/slayer/blob/main/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmotleyai%2Fslayer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmotleyai%2Fslayer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmotleyai%2Fslayer/lists"}