Skip to content

The semantic layer

The semantic layer is the curated map between business language and your Postgres schema. Agents do not guess table names from raw information_schema dumps alone — they consult entity files you version in git.

Semantic-layer files live as YAML under <consumer-repo>/semantic/, one file per entity, filename = entity name + .yml. A Zod schema at @arivie/semantic validates every file at lint time and runtime; the schema is the source of truth for allowed and required fields.

Minimum fields per entity: name, description, grain, primary_key, measures[], dimensions[], segments[], joins[], example_questions[], example_queries[], columns[], hints[], with per-column pii: boolean (default false).

The CLI command arivie add entity <name> scaffolds a starter entity; arivie lint validates the layer.

Mode is auto-detected from semantic-layer token count; consumers override via semantic.mode in config.

ModeWhenMechanism
preloadFew entities (< ~30; ~10k tokens)Entire layer flattened into agent system prompt
indexedLarge catalogsMastra Vector over chunked paragraphs; agent retrieves on demand

In preload mode, the full semantic layer is injected into the agent’s instructions. In indexed mode, the agent uses embedding-based retrieval to pull relevant entity definitions on demand.

Set mode explicitly in config:

defineArivie({
// ...
semantic: {
path: "./semantic",
mode: "auto", // "preload" | "indexed" | "auto"
},
});

When mode is "indexed" (or "auto" resolves to it), you must also provide an embeddings config with a provider, vector store, and index name.

@arivie/workspace implements SemanticLayerFilesystem over the semantic directory as read-only. Write attempts throw immediately — the semantic layer is text in the consumer’s repo, not a studio UI.

For programmatic use, defineEntity and composeSemantic let you build the semantic layer in TypeScript instead of YAML:

import { defineEntity, composeSemantic } from "@arivie/core";
const orders = defineEntity({
name: "orders",
description: "Customer order records",
grain: "one row per order",
primary_key: "order_id",
measures: [
{ name: "revenue", type: "numeric", sql: "SUM(amount)" },
],
dimensions: [
{ name: "order_date", type: "timestamp", column: "created_at" },
],
});
const layer = composeSemantic({ entities: [orders], outputDir: "./semantic" });

This writes validated .yml files to disk and returns the in-memory SemanticLayer for direct use in defineArivie.

  • examples/with-nextjs/semantic/ — five entities (customers, orders, products, line_items, invoices).
  • examples/kitchen-sink/semantic/ — hospitality ops entities with schedules, skills, and triggers.
  • examples/woocommerce-orders-postgres-kitchen-sink/semantic/ — 13 WooCommerce analytics entities.