Skip to content
meaningforgePublic

About

Metis turns agent intent into governed, reproducible, engine-neutral queries over shared semantic assets through semantic discovery, resolution, validation, planning, and compilation.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

48 Commits

Folders and files

Repository files navigation

Metis — The Unified Semantic Runtime for Agentic Analytics

Metis is an open-source, Ossie-first, engine-neutral semantic layer runtime engine. It sits between AI agents or applications and analytical databases, turning structured requests for metrics and dimensions into deterministic SQL and, when execution is configured, analytical results.

Agents reason. Metis resolves semantics. Engines execute.

For example, an agent asks for total revenue by region. Metis resolves the metric definition and compatible dimension from an Ossie model, plans the required joins and aggregations, and generates SQL for the selected database. The same semantic definitions serve the CLI, MCP, REST, and embedded Go APIs.

  • Ossie-first: Apache Ossie models define metrics, dimensions, relationships, and ontology concepts that Metis discovers, validates, and resolves.
  • Engine-neutral: semantic resolution and planning are shared across database targets. Renderers generate dialect-specific SQL; execution backends manage database access. Built-in targets are Doris, ClickHouse, and DuckDB.
  • Deterministic: structured semantic requests go through validation, resolution, planning, and compilation. Metric definitions and relationship rules come from the model. Cumulative averages retain and merge their sum and count state instead of averaging already-finalized period averages. Filtered custom-calendar rolling windows preserve the preceding logical periods required for calculation and apply the requested time range to the final output.
  • Ready for analytical workflows: discover semantic assets, compile SQL, query metrics, compare periods, and analyze metric-change attribution.
Agent or application
        |
        | metrics, dimensions, filters, time ranges
        v
      Metis <----- Apache Ossie models
        |
        +--- discover / validate / resolve / plan
        |
        +--- compile SQL ---> database client of your choice
        |
        +--- execute through a configured backend ---> analytical results

Compilation works without a database connection. Execution adds connection management, cancellation, timeouts, and output limits. MCP and REST expose the same runtime services that Go applications can embed directly.

Choose your entry point

Tool or interface Use it to
metis Validate and compile semantic models offline, manage local projects, or run the standalone semantic runtime.
MCP Give an agent tools for semantic discovery, SQL compilation, and bounded analytics over stdio or HTTP.
REST Integrate semantic discovery, compilation, explanation, and analytics into applications.
a2sbench Run repeatable agent analytics experiments and inspect correctness, readiness, and execution evidence.
Go packages Compose a runtime with your own configuration, policies, and database integrations.

Run from source

Requires Go 1.25 or later. The default binary does not require CGO.

git clone https://github.com/meaningforge/metis.git
cd metis
go build -o bin/metis ./cmd/metis
bin/metis validate --project demo examples/demo/models/sales.ossie.yaml

The example runtime configuration is examples/demo/metis.yaml. It registers a local project manifest that points to Ossie model files. Update those files and your DataSource configuration locally, then restart the runtime to apply changes.

Connect an MCP client

A local MCP client can launch Metis as a stdio subprocess. Replace the absolute paths below with the location of your checkout:

{
  "mcpServers": {
    "metis": {
      "command": "/absolute/path/to/metis/bin/metis",
      "args": ["mcp", "--config", "/absolute/path/to/metis/examples/demo/metis.yaml"]
    }
  }
}

Start with a request such as: “In the demo project, compile total revenue by region.” The agent can discover the model, select total_revenue and region, and call compile_sql.

MCP tools Purpose
list_projects, list_models, get_model Find and inspect available projects and models.
list_metrics, get_metric Discover metrics and inspect their definitions.
get_dimensions, get_dimension, get_relationships Find compatible dimensions, time grains, and relationships.
search_ontology_concepts, resolve_ontology_concept Map business concepts to semantic assets.
compile_sql Validate a semantic request and return SQL with an output schema.
query_metrics, get_dimension_values Retrieve bounded metric results and live dimension values.
compare_metrics Compare metrics across two periods, including values and changes.
attribute_metric Decompose metric changes using supported additive or ratio metrics.

Tools that retrieve data require a configured execution backend. Metric-change attribution provides a numerical decomposition; interpreting its business causes remains the caller's task.

Serve MCP and REST over HTTP

Configure a shared bearer token and start the server:

export METIS_API_KEY='replace-with-your-own-secret'
bin/metis serve --config examples/demo/metis.yaml --addr 127.0.0.1:8080

Connect to http://127.0.0.1:8080/mcp with Authorization: Bearer <your-token>. The REST endpoints under /v1/** use the same authentication and semantic services. /healthz and /readyz are public health endpoints. Local stdio runs under the subprocess owner's permissions.

For example, compile total revenue grouped by region:

curl -fsS http://127.0.0.1:8080/v1/compile-sql \
  -H "Authorization: Bearer $METIS_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "dialect": "DUCKDB",
    "query": {
      "project": "demo",
      "model": "sales",
      "metrics": [{"name": "total_revenue"}],
      "dimensions": [{"name": "region"}]
    }
  }'

The response includes sql_render_result and output_schema. This endpoint compiles the query without executing it. /v1/explain accepts the same request shape and returns SQLExplainResult: semantic planning evidence, the same sql_render_result and output_schema as Compile, and any compilation warnings.

Public filter operands are strings or string arrays. The Resolver interprets them using the referenced semantic datatype, so an Integer value of "9007199254740993", a Decimal value of "0.10000000000000000001", and a Boolean value of "true" become typed database parameters without asking API clients to reproduce database types in JSON. Incompatible or out-of-range operands return INVALID_FILTER_VALUE without disclosing the value. The Resolver also rejects ordered comparisons for Boolean and Opaque fields and validates Date, Time, DateTime, and DateTimeTz literals before planning. A query targets one selected data source; Metis does not perform cross-database query execution. Explain generates SQL without executing it.

To filter source metrics by matching rows on one declared detail relationship without duplicating source measures, use a relationship-existence predicate:

{
  "metrics": [{"name": "order_revenue"}],
  "filters": {
    "kind": "exists",
    "relationship": "orders_to_items",
    "where": {
      "kind": "filter",
      "filter": {"field": "items.category", "operator": "eq", "value": "target"}
    }
  }
}

This compiles to a correlated EXISTS; related rows decide membership but do not change the source grain. See the Agent query contract for the bounded V1 shape and rejection rules.

Offline tools

Semantic authoring commands use metis semantic; the former metis project group is removed without an alias. --project and project.yaml still identify the Project namespace and its manifest.

The metis model, metis semantic, and metis query commands work offline. Use them to validate and inspect models, compare projects, or generate SQL without starting a server, connecting to a database, or resolving secrets.

go build -o bin/metis ./cmd/metis
bin/metis query compile \
  --model examples/demo/models/sales.ossie.yaml \
  --dialect DUCKDB --metric total_revenue --dimension region

Use --dialect DORIS, CLICKHOUSE, or DUCKDB to select a target. Add repeatable --metric, --dimension, and --filter flags, or pass a structured request with --request-json.

metis query compile outputs JSON containing dialect, sql, and optional parameters. SQL retains its placeholders; pass parameter values in order to your database driver. Values are never interpolated into SQL text.

Command Purpose
metis query compile Compile a semantic request into SQL and parameters as JSON.
metis model validate, metis model inspect Validate an Ossie document or inspect its metadata.
metis semantic validate [--offline], metis semantic inspect Load and check a complete semantic project without database connections.
metis semantic validate --online Inspect query dependencies and check Doris/ClickHouse or optional DuckDB EXPLAIN acceptance.
metis semantic diff Compare two local semantic project inputs.
metis semantic init Generate a reviewable Ossie project from catalog evidence and an explicit map, offline.
metis semantic test --mode compile Check project-owned compile expectations in CI without connecting to a database.
metis semantic test --mode runtime Assert metric results against an externally prepared database fixture; emit JSON and optional JUnit.
metis model format Format a model file.
bin/metis semantic validate --project demo --config examples/demo/project.yaml
bin/metis model inspect --model examples/demo/models/sales.ossie.yaml

Validation is offline by default. Explicit online validation requires a deployment configuration, query inventory and a fresh report path:

bin/metis semantic validate --online --project sales --config ./metis.yaml \
  --queries ./queries.json --output ./validation.json

See online validation for modes, authorization, parameter support and report coverage.

ClickHouse supports server-bound query and policy parameters during online validation. Doris parameterized validation remains explicitly unsupported; unparameterized validation is available for both backends.

Run the demo compile suite against a complete project. The command writes a private JSON report and exits nonzero on a failed or incomplete case:

bin/metis semantic test --mode compile --project demo \
  --config examples/demo/project.yaml --suite examples/demo/checks/compile.yaml \
  --dialect DORIS --output ./compile-report.json

See the regression-suite contract for assertion syntax, limits, and exit codes, and the runtime fixture example for Doris/ClickHouse setup. Both modes support --junit-output; runtime currently supports query_metrics.

These commands test your project's business definitions, not Metis engine conformance or custom authorization. Fixture setup and CI orchestration stay external; the CLI is not a general-purpose testing framework.

Execute queries

To start a model from metadata, use the offline authoring example:

bin/metis semantic init --catalog examples/authoring/catalog-doris.json \
  --mapping examples/authoring/model-map.yaml --output ./candidate-sales
bin/metis semantic validate --project sales --config ./candidate-sales/project.yaml

The generator selects only mapped fields and optional technical row counts. Review its report and author business metrics and relationships before adoption. The authoring contract defines supported schemas and mappings. To capture metadata from Doris or ClickHouse first:

bin/metis catalog inspect --config ./metis.yaml --project sales \
  --data-source warehouse --relations examples/authoring/relations.json \
  --output ./catalog.json

Only explicitly selected, qualified relations are inspected; there is no database crawl or row sampling. The command authorizes before reading deployment/source configuration or resolving credentials. Local CLI authoring uses the operator's OS/database identity; remote embedders must enforce Project author and their physical metadata access policy. The snapshot feeds semantic init; successful inspection does not prove SELECT permission. Follow the Doris/ClickHouse table-to-query walkthrough for disposable setup data, explicit business-model review, and verified query results through the CLI and authenticated REST interface.

To enable execution, reference a named DataSource from your project registration and define it in a local DataSource registry. The DataSource type selects the database backend and SQL renderer.

The default build includes Doris and ClickHouse execution backends. To enable DuckDB execution, catalog inspection and online validation, build with CGO and the duckdb tag:

CGO_ENABLED=1 go build -tags duckdb -o bin/metis ./cmd/metis

The local DuckDB walkthrough covers an existing read-only database file through catalog capture, reviewed project generation, parameterized online validation and result tests, without Docker. Offline generation from DuckDB snapshots and DuckDB SQL compilation work with the default build. Compile-only deployments require no database credentials. The execution runtime manages connections, secrets, cancellation, timeouts, and output limits.

a2sbench: Agent benchmarks for Metis Core

A2SBench (Agent-to-SQL Benchmark) evaluates how agents use Metis Core to complete analytical tasks. It runs frozen questions with explicit budgets, scores independently reviewed result expectations, records attempts and query evidence, and produces machine-readable reports. Metis MCP is the system under test; OKF assets/direct SQL provide controlled baselines. Neutrality means fair scoring and comparable experimental conditions, not a multi-semantic-engine platform. The oracle must not favor Metis SQL spelling or output aliases.

New report identifiers use the a2sbench prefix. Branding migrations must preserve experiment identities, tested interface names, scores and raw results; they do not constitute new benchmark runs. Input and agent-driver protocols retain their existing versions independently of the executable name.

These tools have separate responsibilities: metis semantic test checks an author's explicit compile/result expectations without running an agent, while a2sbench owns frozen benchmark suites, agent runners, scoring and comparisons. Metis does not expose benchmark commands; A2SBench does not replace semantic authoring, catalog capture or project-owned regression commands. Both use the existing semantic/query services rather than implementing another query engine.

A run selects one interface: metis-mcp for Metis tools, or okf for catalog-derived semantic files. Running the same suite with the same agent and model through each interface enables a paired comparison.

Build with embedded DuckDB support and inspect the available commands:

make a2sbench-build
bin/a2sbench --help
bin/a2sbench run --help

Agent runs require an installed, authenticated agent CLI and model access. The runner supports Codex, Claude Code, Pi, and a generic driver. The DuckDB build also requires CGO and a C toolchain. Start with the smoke suite and set the model identifiers to those used by your agent:

bin/a2sbench run \
  --suite smoke \
  --arm metis-mcp \
  --agent codex \
  --model '<model-id>' \
  --provider '<provider>' \
  --model-version '<model-version>' \
  --output ./a2sbench-results/smoke-metis

Completed runs contain manifest.json, collection.json, attempts.jsonl, and report.json. Repeat an interrupted command with --resume to keep completed work. Use --detach for a background run and a2sbench stop <output-directory> to stop it.

For a paired experiment, repeat the run with --arm okf and a separate output directory, then compare both collections:

bin/a2sbench analyze \
  --input ./a2sbench-results/smoke-okf \
  --input ./a2sbench-results/smoke-metis \
  --output ./a2sbench-results/comparison.json

Additional commands cover workload generation (gen), catalog-derived file creation (okfgen), reports (report), and attribution and comparison experiments. Use bin/a2sbench <command> --help for their inputs and options. Agent benchmark runs are separate from the standard correctness tests.

Use your own models

  1. Copy examples/demo into your project directory.
  2. Add your Ossie model files under models/.
  3. Update project.yaml to select those files and register your project in metis.yaml.
  4. Validate the project with metis semantic validate, then start metis serve or metis mcp with your runtime configuration.

Model paths are resolved relative to the project manifest. A runtime can register multiple projects; see examples/multi-project/metis.yaml.

Embed in a Go application

Import packages from github.com/meaningforge/metis and pin a version or commit in your application's go.mod.

Task Entry point
Load a runtime from local configuration bootstrap.LoadRuntime
Build a runtime from configuration and model bytes bootstrap.NewRuntime, RuntimeInput, ProjectInput
Serve REST and MCP with an identity verifier hosting.NewHTTPHandler
Configure project access and data constraints bootstrap.WithProjectAuthorizer, WithAssetVisibilityPolicy, WithDataAccessPolicy
Supply database backends and secret resolution bootstrap.WithBackendRegistry, WithSecretResolver
Load model documents from memory source.LoadProjectDocuments
Replace an active semantic snapshot runtime.Manager.Replace
Close database pools bootstrap.Runtime.Close

Runtime integration packages live under app/bootstrap, app/hosting, app/auth, and app/service. Database extension interfaces live under renderer and execution. Integrations use ordinary Go interfaces and compile-time composition. Passing an explicit nil asset visibility policy rejects runtime initialization. A request pinned again by the same runtime keeps its snapshot; pinning it through another runtime creates a new scope for that runtime.

The embedding example constructs a runtime from memory, applies access policies, and replaces a semantic snapshot. Before v1, pin exact versions and run compatibility tests when upgrading.

Development

The documentation and license checks require Python 3 in addition to Go.

go mod tidy
make check
make test-e2e
make test-duckdb-backend

make check runs documentation and source contract checks, go vet, unit tests, sample models, semantic conformance tests, and the quickstart verification. The Apache Ossie fixture check downloads a pinned upstream commit. For an offline run, set OSSIE_GIT_DIR to a local Apache Ossie Git object directory containing that commit. Database integration tests require explicitly configured services and run separately.

CI reuses Go module/build caches. Ordinary code PRs run the complete correctness, embedded DuckDB, E2E and container checks; full release archives additionally run for packaging, dependency, license, CI or platform-specific changes, on main code pushes, and for manual dispatch. Documentation-only changes use the docs gate (changes to packaged license files still trigger full checks). Snapshot packaging shares the same commit's correctness gate rather than repeating its tests through GoReleaser hooks. Tag releases run make release-check before publishing. See the CI scope classifier.

License

Apache License 2.0. Third-party attribution and license texts are available in NOTICE, THIRD_PARTY_NOTICES, and licenses/. Run make licenses after updating dependencies; make licenses-check verifies the bundle included in release archives and images.

Design and RFCs

See the documentation guide for architecture, public contracts, model authoring, execution, and A2SBench. Core RFCs record proposals and design rationale, with explicit lifecycle status.

About

Metis turns agent intent into governed, reproducible, engine-neutral queries over shared semantic assets through semantic discovery, resolution, validation, planning, and compilation.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages