{"id":45164333,"url":"https://github.com/ralfbecher/orionbelt-semantic-layer","last_synced_at":"2026-04-02T12:09:26.474Z","repository":{"id":338884124,"uuid":"1154643037","full_name":"ralfbecher/orionbelt-semantic-layer","owner":"ralfbecher","description":"API-first semantic engine and query planner for AI agents that compiles declarative YAML models into optimized, dialect-specific SQL across BigQuery, PostgreSQL, Snowflake, ClickHouse, Dremio, Databricks, DuckDB, and MySQL.","archived":false,"fork":false,"pushed_at":"2026-03-31T06:20:06.000Z","size":10382,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-31T07:48:37.211Z","etag":null,"topics":["agentic-ai","ai-analytics","ai-workflow","bigquery","business-intelligence","clickhouse","data-analytics","databricks","dremio","duckdb","mcp","mcp-server","model-context-protocol","mysql","postgresql","rest-api","semantic-layer","snowflake","yaml"],"latest_commit_sha":null,"homepage":"https://ralforion.com/orionbelt-semantic-layer/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ralfbecher.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG-versions.md","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":"CLA.md"}},"created_at":"2026-02-10T16:10:48.000Z","updated_at":"2026-03-31T06:20:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ralfbecher/orionbelt-semantic-layer","commit_stats":null,"previous_names":["ralfbecher/orionbelt-semantic-layer"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/ralfbecher/orionbelt-semantic-layer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ralfbecher","download_url":"https://codeload.github.com/ralfbecher/orionbelt-semantic-layer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ralfbecher%2Forionbelt-semantic-layer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["agentic-ai","ai-analytics","ai-workflow","bigquery","business-intelligence","clickhouse","data-analytics","databricks","dremio","duckdb","mcp","mcp-server","model-context-protocol","mysql","postgresql","rest-api","semantic-layer","snowflake","yaml"],"created_at":"2026-02-20T06:30:47.689Z","updated_at":"2026-04-02T12:09:26.459Z","avatar_url":"https://github.com/ralfbecher.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/ORIONBELT_Logo.png\" alt=\"OrionBelt Logo\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eOrionBelt Semantic Layer\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eCompile and execute YAML semantic models as analytical SQL across multiple database dialects\u003c/strong\u003e\u003c/p\u003e\n\n[![GitHub stars](https://img.shields.io/github/stars/ralfbecher/orionbelt-semantic-layer?style=social)](https://github.com/ralfbecher/orionbelt-semantic-layer)\n[![Version 1.2.2](https://img.shields.io/badge/version-1.2.2-purple.svg)](https://github.com/ralfbecher/orionbelt-semantic-layer/releases)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n[![License: BSL 1.1](https://img.shields.io/badge/License-BSL_1.1-orange.svg)](https://github.com/ralfbecher/orionbelt-semantic-layer/blob/main/LICENSE)\n[![Docker Hub](https://img.shields.io/docker/pulls/ralforion/orionbelt-api?logo=docker\u0026label=Docker%20Hub)](https://hub.docker.com/repositories/ralforion)\n[![FastAPI](https://img.shields.io/badge/FastAPI-0.128+-009688.svg?logo=fastapi\u0026logoColor=white)](https://fastapi.tiangolo.com)\n[![Pydantic v2](https://img.shields.io/badge/Pydantic-v2-E92063.svg?logo=pydantic\u0026logoColor=white)](https://docs.pydantic.dev)\n[![Gradio](https://img.shields.io/badge/Gradio-5.0+-F97316.svg?logo=gradio\u0026logoColor=white)](https://www.gradio.app)\n[![sqlglot](https://img.shields.io/badge/sqlglot-26.0+-4B8BBE.svg)](https://github.com/tobymao/sqlglot)\n[![Arrow Flight SQL](https://img.shields.io/badge/Arrow_Flight_SQL-ready-D22128.svg?logo=apachearrow\u0026logoColor=white)](https://arrow.apache.org/docs/format/FlightSql.html)\n[![DB-API 2.0](https://img.shields.io/badge/DB--API_2.0-PEP_249-3776AB.svg?logo=python\u0026logoColor=white)](https://peps.python.org/pep-0249/)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://docs.astral.sh/ruff/)\n[![mypy](https://img.shields.io/badge/type--checked-mypy-blue.svg)](https://mypy-lang.org)\n\n[![BigQuery](https://img.shields.io/badge/BigQuery-669DF6.svg?logo=googlebigquery\u0026logoColor=white)](https://cloud.google.com/bigquery)\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1.svg?logo=postgresql\u0026logoColor=white)](https://www.postgresql.org)\n[![Snowflake](https://img.shields.io/badge/Snowflake-29B5E8.svg?logo=snowflake\u0026logoColor=white)](https://www.snowflake.com)\n[![ClickHouse](https://img.shields.io/badge/ClickHouse-FFCC01.svg?logo=clickhouse\u0026logoColor=black)](https://clickhouse.com)\n[![Dremio](https://img.shields.io/badge/Dremio-31B48D.svg)](https://www.dremio.com)\n[![Databricks](https://img.shields.io/badge/Databricks-FF3621.svg?logo=databricks\u0026logoColor=white)](https://www.databricks.com)\n[![DuckDB](https://img.shields.io/badge/DuckDB-FFF000.svg?logo=duckdb\u0026logoColor=black)](https://duckdb.org)\n[![MySQL](https://img.shields.io/badge/MySQL-4479A1.svg?logo=mysql\u0026logoColor=white)](https://www.mysql.com)\n\nOrionBelt Semantic Layer is an **API-first** semantic engine and query planner for AI agents that compiles and executes declarative YAML model definitions as optimized SQL for BigQuery, ClickHouse, Databricks, Dremio, DuckDB/MotherDuck, MySQL, Postgres, and Snowflake. It provides a unified abstraction over your data warehouse, so analysts and applications can query using business concepts (dimensions, measures, metrics) instead of raw SQL. Every capability — model loading, validation, query compilation and execution, and diagram generation — is exposed through a REST API, making OrionBelt easy to integrate into any application, workflow, or AI assistant.\n\n## Features\n\n- **8 SQL Dialects** — BigQuery, ClickHouse, Databricks, Dremio, DuckDB/MotherDuck, MySQL, Postgres, Snowflake with dialect-specific optimizations\n- **AST-Based SQL Generation** — Custom SQL AST ensures correct, injection-safe SQL (no string concatenation)\n- **OrionBelt ML (OBML)** — YAML-based semantic models with data objects, dimensions, measures, metrics (derived and cumulative), and joins\n- **Cumulative Metrics** — Running totals, rolling windows, and grain-to-date (MTD/YTD) via window functions with configurable aggregation types\n- **Star Schema \u0026 CFL Planning** — Automatic join path resolution with Composite Fact Layer support for multi-fact queries and dimension-only queries through intermediate tables\n- **Dimension Exclusion** — Anti-join queries via `dimensionsExclude` flag to find non-existing combinations (e.g., directors and producers who never collaborated)\n- **Vendor-Specific SQL Validation** — Post-generation syntax validation via sqlglot for each target dialect (non-blocking)\n- **Validation with Source Positions** — Precise error reporting with line/column numbers from YAML source, including join graph analysis (cycle and multipath detection, secondary join constraints)\n- **Session Management** — TTL-scoped sessions with per-client model stores\n- **ER Diagram Generation** — Mermaid ER diagrams via API and Gradio UI with theme support, zoom, and secondary join visualization\n- **REST API** — FastAPI-powered session endpoints for model loading, validation, compilation, execution, diagram generation, and management\n- **MCP Server** — Available as a separate thin client in [orionbelt-semantic-layer-mcp](https://github.com/ralfbecher/orionbelt-semantic-layer-mcp) — delegates to the REST API via HTTP, deployable independently (e.g. to Prefect Horizon)\n- **AI Integrations** — Ready-to-use tools for [LangChain](integrations/langchain/), [OpenAI Agents SDK](integrations/openai-agents-sdk/), [CrewAI](integrations/crewai/), [Google ADK](integrations/google-adk/), [Vercel AI SDK](integrations/vercel-ai-sdk/), [n8n](integrations/n8n/), and [ChatGPT Custom GPT](integrations/chatgpt-custom-gpt/)\n- **Gradio UI** — Interactive web interface for model editing, query testing, and SQL compilation with live validation feedback\n- **[OSI](https://github.com/open-semantic-interchange/OSI) Interoperability** — Bidirectional conversion between OBML and the Open Semantic Interchange format via REST API (`/convert`) and Gradio UI, with validation for both directions\n- **DB-API 2.0 Drivers** — PEP 249 drivers for all 8 databases with transparent OBML-to-SQL compilation via REST API\n- **Arrow Flight SQL** — Embedded gRPC server for DBeaver, Tableau, and Power BI — single container, two ports (8080 + 8815)\n- **Plugin Architecture** — Extensible dialect system with capability flags and registry\n\n## Quick Start\n\n### Prerequisites\n\n- Python 3.12+\n- [uv](https://docs.astral.sh/uv/) package manager\n\n### Installation\n\n```bash\ngit clone https://github.com/ralfbecher/orionbelt-semantic-layer.git\ncd orionbelt-semantic-layer\nuv sync\n```\n\n### Run Tests\n\n```bash\nuv run pytest\n```\n\n### Start the REST API Server\n\n```bash\nuv run orionbelt-api\n# or with reload:\nuv run uvicorn orionbelt.api.app:create_app --factory --reload\n```\n\nThe API is available at `http://127.0.0.1:8000`. Interactive docs at `/docs` (Swagger UI) and `/redoc`.\n\n### Interactive Jupyter Notebook\n\nThe [Quickstart Notebook](examples/quickstart.ipynb) walks through the full workflow using TPC-H in DuckDB — explore the model, compile queries across dialects, execute against real data, and see multi-fact CFL, secondary join paths, and complex measures in action. No cloud database needed.\n\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ralfbecher/orionbelt-semantic-layer/blob/main/examples/quickstart_colab.ipynb) — Run the full quickstart directly in Google Colab (requires Python 3.12 runtime).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/quickstart_notebook.png\" alt=\"Interactive Jupyter Notebook\" width=\"900\"\u003e\n\u003c/p\u003e\n\n## Example\n\n### Define a Semantic Model\n\n```yaml\n# yaml-language-server: $schema=schema/obml-schema.json\nversion: 1.0\n\ndataObjects:\n  Customers:\n    code: CUSTOMERS\n    database: WAREHOUSE\n    schema: PUBLIC\n    synonyms: [client, buyer, purchaser]\n    columns:\n      Customer ID:\n        code: CUSTOMER_ID\n        abstractType: string\n      Country:\n        code: COUNTRY\n        abstractType: string\n\n  Orders:\n    code: ORDERS\n    database: WAREHOUSE\n    schema: PUBLIC\n    columns:\n      Order ID:\n        code: ORDER_ID\n        abstractType: string\n      Order Customer ID:\n        code: CUSTOMER_ID\n        abstractType: string\n      Price:\n        code: PRICE\n        abstractType: float\n        numClass: non-additive\n      Quantity:\n        code: QUANTITY\n        abstractType: int\n        numClass: additive\n    joins:\n      - joinType: many-to-one\n        joinTo: Customers\n        columnsFrom:\n          - Order Customer ID\n        columnsTo:\n          - Customer ID\n\ndimensions:\n  Country:\n    dataObject: Customers\n    column: Country\n    resultType: string\n\nmeasures:\n  Revenue:\n    resultType: float\n    aggregation: sum\n    expression: \"{[Orders].[Price]} * {[Orders].[Quantity]}\"\n    synonyms: [sales, income, turnover]\n```\n\nThe `yaml-language-server` comment enables schema validation in editors that support it (VS Code with YAML extension, IntelliJ, etc.). The JSON Schema is at [`schema/obml-schema.json`](schema/obml-schema.json).\n\n### Define a Query\n\nQueries select dimensions and measures by their business names:\n\n```yaml\nselect:\n  dimensions:\n    - Country\n  measures:\n    - Revenue\nlimit: 100\n```\n\n### Compile to SQL (Python)\n\n```python\nfrom orionbelt.compiler.pipeline import CompilationPipeline\nfrom orionbelt.models.query import QueryObject, QuerySelect\nfrom orionbelt.parser.loader import TrackedLoader\nfrom orionbelt.parser.resolver import ReferenceResolver\n\n# Load and parse the model\nloader = TrackedLoader()\nraw, source_map = loader.load(\"model.yaml\")\nmodel, result = ReferenceResolver().resolve(raw, source_map)\n\n# Define a query\nquery = QueryObject(\n    select=QuerySelect(\n        dimensions=[\"Country\"],\n        measures=[\"Revenue\"],\n    ),\n    limit=100,\n)\n\n# Compile to SQL\npipeline = CompilationPipeline()\nresult = pipeline.compile(query, model, \"postgres\")\nprint(result.sql)\n```\n\n**Generated SQL (Postgres):**\n\n```sql\nSELECT\n  \"Customers\".\"COUNTRY\" AS \"Country\",\n  SUM(\"Orders\".\"PRICE\" * \"Orders\".\"QUANTITY\") AS \"Revenue\"\nFROM WAREHOUSE.PUBLIC.ORDERS AS \"Orders\"\nLEFT JOIN WAREHOUSE.PUBLIC.CUSTOMERS AS \"Customers\"\n  ON \"Orders\".\"CUSTOMER_ID\" = \"Customers\".\"CUSTOMER_ID\"\nGROUP BY \"Customers\".\"COUNTRY\"\nLIMIT 100\n```\n\nChange the dialect to `\"bigquery\"`, `\"clickhouse\"`, `\"databricks\"`, `\"dremio\"`, `\"duckdb\"`, `\"mysql\"`, or `\"snowflake\"` to get dialect-specific SQL.\n\n\u003e **Interactive notebook:** Try the full workflow in [`examples/quickstart.ipynb`](examples/quickstart.ipynb) — uses the TPC-H dataset in DuckDB to demonstrate multi-dialect compilation, query execution, multi-fact CFL, metrics, filters, and ER diagrams.\n\n### Use the REST API with Sessions\n\n```bash\n# Start the server\nuv run orionbelt-api\n\n# Create a session\ncurl -s -X POST http://127.0.0.1:8000/v1/sessions | jq\n# → {\"session_id\": \"a1b2c3d4e5f6\", \"model_count\": 0, ...}\n\n# Load a model into the session\ncurl -s -X POST http://127.0.0.1:8000/v1/sessions/a1b2c3d4e5f6/models \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"model_yaml\": \"version: 1.0\\ndataObjects:\\n  ...\"}' | jq\n# → {\"model_id\": \"abcd1234\", \"data_objects\": 2, ...}\n\n# Compile a query\ncurl -s -X POST http://127.0.0.1:8000/v1/sessions/a1b2c3d4e5f6/query/sql \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model_id\": \"abcd1234\",\n    \"query\": {\"select\": {\"dimensions\": [\"Country\"], \"measures\": [\"Revenue\"]}},\n    \"dialect\": \"postgres\"\n  }' | jq .sql\n```\n\n## Architecture\n\n```\nYAML Model          Query Object\n    |                    |\n    v                    v\n ┌───────────┐    ┌──────────────┐\n │  Parser   │    │  Resolution  │  ← Phase 1: resolve refs, select fact table,\n │  (ruamel) │    │              │    find join paths, classify filters\n └────┬──────┘    └──────┬───────┘\n      │                  │\n      v                  v\n SemanticModel    ResolvedQuery\n      │                  │\n      │    ┌─────────────┘\n      │    │\n      v    v\n ┌───────────────┐\n │   Planner     │  ← Phase 2: Star Schema or CFL (multi-fact)\n │  (star / cfl) │    builds SQL AST with joins, grouping, CTEs\n └───────┬───────┘\n         │\n         v\n    SQL AST (Select, Join, Expr...)\n         │\n         v\n ┌───────────────┐\n │   Codegen     │  ← Phase 3: dialect renders AST to SQL string\n │  (dialect)    │    handles quoting, time grains, functions\n └───────┬───────┘\n         │\n         v\n    SQL String (dialect-specific)\n```\n\n## Gradio UI\n\nOrionBelt includes an interactive web UI built with [Gradio](https://www.gradio.app/) for exploring and testing the compilation pipeline visually.\n\n### Local Development\n\nFor local development, the Gradio UI is automatically mounted at `/ui` on the REST API server when the `ui` extra is installed:\n\n```bash\nuv sync --extra ui\nuv run orionbelt-api\n# → API at http://localhost:8000\n# → UI  at http://localhost:8000/ui\n```\n\n### Standalone Mode\n\nThe UI can also run as a separate process, connecting to the API via `API_BASE_URL`:\n\n```bash\nuv sync --extra ui\n\n# Start the REST API (required backend)\nuv run orionbelt-api \u0026\n\n# Launch the Gradio UI (standalone on port 7860)\nAPI_BASE_URL=http://localhost:8000 uv run orionbelt-ui\n```\n\n### API and UI Live Demo Hosting at Google Cloud Run\n\nOrionBelt Semantic Layer API and UI is available as a hosted live demo:\n\n\u003e **[http://35.187.174.102/ui](http://35.187.174.102/ui/?__theme=dark)**\n\nAPI endpoint: `http://35.187.174.102` — Interactive docs: [Swagger UI](http://35.187.174.102/docs) | [ReDoc](http://35.187.174.102/redoc)\n\nThe API and UI services share a single IP via a Google Cloud Application Load Balancer with path-based routing. Cloud Armor provides WAF protection.\n\nThe API and UI are deployed as **separate Cloud Run services** behind a shared load balancer. The API image (`Dockerfile`) excludes Gradio for faster cold starts (~2-3s vs ~12s), while the UI image (`Dockerfile.ui`) connects to the API via `API_BASE_URL`:\n\n```\nLoad Balancer (single IP)\n  ├── /ui/*     → orionbelt-ui   (Gradio)\n  └── /*        → orionbelt-api  (FastAPI)\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/ui-sqlcompiler-dark.png\" alt=\"SQL Compiler in Gradio UI (dark mode)\" width=\"900\"\u003e\n\u003c/p\u003e\n\nThe UI provides:\n\n- **Side-by-side editors** — OBML model (YAML) and query (YAML) with syntax highlighting\n- **Dialect selector** — Switch between BigQuery, ClickHouse, Databricks, Dremio, DuckDB, MySQL, Postgres, and Snowflake\n- **One-click compilation** — Compile button generates formatted SQL output\n- **SQL validation feedback** — Warnings and validation errors from sqlglot are displayed as comments above the generated SQL\n- **ER Diagram tab** — Visualize the semantic model as a Mermaid ER diagram with left-to-right layout, FK annotations, dotted lines for secondary joins, and an adjustable zoom slider\n- **OSI Import / Export** — Import OSI format models (converted to OBML) and export OBML models to OSI format, with validation feedback\n- **Dark / light mode** — Toggle via the header button; all inputs and UI state are persisted across mode switches\n\nThe bundled example model (`examples/sem-layer.obml.yml`) is loaded automatically on startup.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/ui-er-diagram-dark.png\" alt=\"ER Diagram in Gradio UI (dark mode)\" width=\"900\"\u003e\n\u003c/p\u003e\n\nThe ER diagram is also available as download (MD, or PNG) or via the REST API.\n\n## Docker\n\n### [Docker Hub](https://hub.docker.com/repositories/ralforion)\n\nPre-built multi-platform images (linux/amd64, linux/arm64) are available on Docker Hub:\n\n```bash\n# API-only (REST API on :8080)\ndocker pull ralforion/orionbelt-api\ndocker run -p 8080:8080 ralforion/orionbelt-api\n\n# API + Arrow Flight SQL (REST on :8080, Flight on :8815)\ndocker pull ralforion/orionbelt-flight\ndocker run -p 8080:8080 -p 8815:8815 --env-file .env ralforion/orionbelt-flight\n\n# UI (Gradio on :7860, connects to API)\ndocker pull ralforion/orionbelt-ui\ndocker run -p 7860:7860 \\\n  -e API_BASE_URL=http://host.docker.internal:8080 \\\n  ralforion/orionbelt-ui\n```\n\nSee [docs/drivers.md](docs/drivers.md) for Flight SQL configuration and BI tool setup (DBeaver, Tableau, Power BI).\n\n### Build and Run (from source)\n\nTwo separate images — API-only (fast) and UI (with Gradio):\n\n```bash\n# API image (no Gradio, fast cold starts)\ndocker build -t orionbelt-api .\ndocker run -p 8080:8080 orionbelt-api\n\n# UI image (Gradio, connects to API)\ndocker build -f Dockerfile.ui -t orionbelt-ui .\ndocker run -p 7860:7860 \\\n  -e API_BASE_URL=http://host.docker.internal:8080 \\\n  orionbelt-ui\n```\n\nThe API is available at `http://localhost:8080`. The UI is at `http://localhost:7860`. Sessions are ephemeral (in-memory, lost on container restart).\n\n### Run Integration Tests\n\n```bash\n# Build image and run 15 endpoint tests\n./tests/docker/test_docker.sh\n\n# Skip build (use existing image)\n./tests/docker/test_docker.sh --no-build\n\n# Run 30 tests against a live Cloud Run deployment\n./tests/cloudrun/test_cloudrun.sh https://orionbelt-semantic-layer-mw2bqg2mva-ew.a.run.app\n```\n\n## DB-API 2.0 Drivers \u0026 Arrow Flight SQL\n\nOrionBelt provides **PEP 249 DB-API 2.0 drivers** for 8 databases and an **Arrow Flight SQL server** that enables BI tools like DBeaver, Tableau, and Power BI to run OBML queries directly.\n\n| Package               | Database                | Native Connector             | Arrow Support         |\n| --------------------- | ----------------------- | ---------------------------- | --------------------- |\n| `ob-driver-core`      | — (shared foundation)   | —                            | —                     |\n| `ob-bigquery`         | BigQuery                | `google-cloud-bigquery`      | `to_arrow()`          |\n| `ob-duckdb`           | DuckDB                  | `duckdb`                     | `fetch_arrow_table()` |\n| `ob-postgres`         | PostgreSQL              | `adbc-driver-postgresql`     | ADBC native           |\n| `ob-snowflake`        | Snowflake               | `snowflake-connector-python` | `fetch_arrow_all()`   |\n| `ob-clickhouse`       | ClickHouse              | `clickhouse-connect`         | `query_arrow()`       |\n| `ob-dremio`           | Dremio                  | `pyarrow.flight`             | Flight native         |\n| `ob-databricks`       | Databricks              | `databricks-sql-connector`   | `fetchall_arrow()`    |\n| `ob-flight-extension` | Arrow Flight SQL server | `pyarrow.flight`             | —                     |\n\nAll drivers work against the OrionBelt REST API in **single-model mode** (`MODEL_FILE` set). OBML queries are compiled transparently via `POST /v1/query/sql` — the user writes OBML, the driver returns SQL results. Plain SQL queries bypass the API entirely.\n\n```python\nimport ob_duckdb\n\nconn = ob_duckdb.connect(database=\":memory:\")\nwith conn.cursor() as cur:\n    # OBML query — compiled via API, executed on DuckDB\n    cur.execute(\"select:\\n  dimensions:\\n    - Region\\n  measures:\\n    - Revenue\\n\")\n    print(cur.fetchall())\n```\n\nThe **Arrow Flight SQL server** (`ob-flight-extension`) runs inside the API process as a daemon thread, enabling JDBC/ODBC BI tools to connect directly. It is designed for on-premise or hybrid deployments — Cloud Run uses the standard API-only image.\n\n```bash\n# On-premise with Flight SQL enabled\ndocker build -f Dockerfile.flight -t orionbelt-flight .\ndocker run -p 8080:8080 -p 8815:8815 \\\n  -v /path/to/models/:/app/models/ \\\n  --env-file .env \\\n  orionbelt-flight\n```\n\nSee **[Drivers Documentation](docs/drivers.md)** for full usage examples, connect() parameters, Flight SQL configuration, Docker Compose setup, and DBeaver/Tableau instructions.\n\n## Configuration\n\nConfiguration is via environment variables or a `.env` file. See `.env.template` for all options:\n\n| Variable                   | Default     | Description                               |\n| -------------------------- | ----------- | ----------------------------------------- |\n| `LOG_LEVEL`                | `INFO`      | Logging level                             |\n| `LOG_FORMAT`               | `console`   | `console` (pretty) or `json` (structured) |\n| `API_SERVER_HOST`          | `localhost` | REST API bind host                        |\n| `API_SERVER_PORT`          | `8000`      | REST API bind port                        |\n| `PORT`                     | —           | Override port (Cloud Run sets this)       |\n| `DISABLE_SESSION_LIST`     | `false`     | Disable `GET /sessions` endpoint          |\n| `SESSION_TTL_SECONDS`      | `1800`      | Session inactivity timeout (30 min)       |\n| `SESSION_CLEANUP_INTERVAL` | `60`        | Cleanup sweep interval (seconds)          |\n| `MODEL_FILE`               | —           | Path to OBML YAML for single-model mode   |\n| `API_BASE_URL`             | —           | API URL for standalone UI                 |\n| `ROOT_PATH`                | —           | ASGI root path for UI behind LB           |\n| `FLIGHT_ENABLED`           | `false`     | Enable Flight SQL + query execution       |\n| `FLIGHT_PORT`              | `8815`      | Arrow Flight SQL gRPC port                |\n| `FLIGHT_AUTH_MODE`         | `none`      | `none` or `token`                         |\n| `FLIGHT_API_TOKEN`         | —           | Static token (when auth mode = token)     |\n| `DB_VENDOR`                | `duckdb`    | Database vendor for query execution       |\n\n### Single-Model Mode\n\nWhen `MODEL_FILE` is set to a path to an OBML YAML file, the server starts in **single-model mode**:\n\n- The model file is validated at startup (the server refuses to start if it's invalid)\n- Every new session is automatically pre-loaded with the configured model\n- Model upload (`POST /v1/sessions/{id}/models`) and removal (`DELETE /v1/sessions/{id}/models/{id}`) return **403 Forbidden**\n- All other endpoints (sessions, query, validate, diagram, etc.) work normally\n\n```bash\n# Start in single-model mode\nMODEL_FILE=./examples/sem-layer.obml.yml uv run orionbelt-api\n```\n\n## Development\n\n```bash\n# Install all dependencies (including dev tools)\nuv sync\n\n# Run the test suite\nuv run pytest\n\n# Lint\nuv run ruff check src/\n\n# Type check\nuv run mypy src/\n\n# Format code\nuv run ruff format src/ tests/\n\n# Build documentation\nuv sync --extra docs\nuv run mkdocs serve\n```\n\n## Documentation\n\nFull documentation is available at the [docs site](https://ralfbecher.github.io/orionbelt-semantic-layer/) or can be built locally:\n\n```bash\nuv sync --extra docs\nuv run mkdocs serve   # http://127.0.0.1:8080\n```\n\n## OSI Interoperability\n\nOrionBelt includes a bidirectional converter between OBML and the [Open Semantic Interchange (OSI)](https://github.com/open-semantic-interchange/OSI) format. The converter handles the structural differences between the two formats — including metric decomposition, relationship restructuring, and lossless `ai_context` preservation via `customExtensions` — with built-in validation for both directions.\n\nThe conversion is available via REST API endpoints:\n\n```bash\n# Convert OSI → OBML\ncurl -X POST http://127.0.0.1:8000/v1/convert/osi-to-obml \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"input_yaml\": \"version: \\\"0.1.1\\\"\\nsemantic_model:\\n  ...\"}' | jq\n\n# Convert OBML → OSI\ncurl -X POST http://127.0.0.1:8000/v1/convert/obml-to-osi \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"input_yaml\": \"version: 1.0\\ndataObjects:\\n  ...\"}' | jq\n```\n\nThe Gradio UI also provides **Import OSI** / **Export to OSI** buttons that use these API endpoints.\n\nSee the [OSI ↔ OBML Mapping Analysis](osi-obml/osi_obml_mapping_analysis.md) for a detailed comparison and conversion reference.\n\n## AI Integrations\n\n| Integration | Language | Description | Guide |\n|-------------|----------|-------------|-------|\n| **LangChain / LangGraph** | Python | 10 async tools + `create_agent` example | [`integrations/langchain/`](integrations/langchain/) |\n| **OpenAI Agents SDK** | Python | 10 function tools + `Agent`/`Runner` example | [`integrations/openai-agents-sdk/`](integrations/openai-agents-sdk/) |\n| **CrewAI** | Python | 10 tools + multi-agent crew example | [`integrations/crewai/`](integrations/crewai/) |\n| **Google ADK** | Python | 10 FunctionTools + Gemini agent example | [`integrations/google-adk/`](integrations/google-adk/) |\n| **Vercel AI SDK** | TypeScript | 10 tools + Next.js API route example | [`integrations/vercel-ai-sdk/`](integrations/vercel-ai-sdk/) |\n| **n8n** | JSON | Workflow templates (batch + AI agent) | [`integrations/n8n/`](integrations/n8n/) |\n| **ChatGPT Custom GPT** | OpenAPI | OpenAPI 3.1 spec + GPT instructions | [`integrations/chatgpt-custom-gpt/`](integrations/chatgpt-custom-gpt/) |\n| **MCP Server** | Python | 10+ tools for Claude, Copilot, Cursor, Windsurf | [separate repo](https://github.com/ralfbecher/orionbelt-semantic-layer-mcp) |\n\nAll REST API integrations use the [shortcut endpoints](#single-model-mode) and work best with OrionBelt running in single-model mode (`MODEL_FILE` set). Each integration also documents the MCP alternative for tools that support it.\n\n## Companion Project\n\n### [OrionBelt Analytics](https://github.com/ralfbecher/orionbelt-analytics)\n\nOrionBelt Analytics is an ontology-based MCP server that analyzes relational database schemas and generates RDF/OWL ontologies with embedded SQL mappings. It connects to PostgreSQL, Snowflake, and Dremio, providing AI assistants with deep structural and semantic understanding of your data.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/architecture.png\" alt=\"OrionBelt Analytics Architecture\" width=\"800\"\u003e\n\u003c/p\u003e\n\nTogether, the two projects form a powerful combination for AI-guided analytical workflows:\n\n- **OrionBelt Analytics** gives the AI contextual knowledge of your database schema, relationships, and business semantics\n- **OrionBelt Semantic Layer** ensures correct, optimized SQL compilation and execution from business concepts (dimensions, measures, metrics)\n\nBy combining both, an AI assistant can navigate your data landscape through ontologies and compile safe, dialect-aware analytical SQL — enabling a seamless end-to-end analytical journey.\n\n## License\n\nCopyright 2025 [RALFORION d.o.o.](https://ralforion.com)\n\nLicensed under the [Business Source License 1.1](LICENSE). The Licensed Work will convert to Apache License 2.0 on 2030-03-16.\n\nBy contributing to this project, you agree to the [Contributor License Agreement](CLA.md).\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ralforion.com\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/ralfbecher/orionbelt-semantic-layer/main/docs/assets/RALFORION_doo_Logo.png\" alt=\"RALFORION d.o.o.\" width=\"200\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fralfbecher%2Forionbelt-semantic-layer/lists"}