# Getting started with the semantic layer - Docs

In this guide you'll take a metric that only exists in people's heads – MRR – and turn it into a governed definition every AI session agrees on. The whole thing is one agent conversation: the agent proposes, you approve, and from then on every client that asks about MRR gets the same number.

**The semantic layer is in alpha**

The semantic layer is in alpha, enabled per organization for a small group of customers. There's no dedicated UI yet – you work with it through MCP tools and SQL. Tool names and behavior may change between releases. Found a bug, or want access? [Contact support](https://app.posthog.com/home#supportModal) and mention the semantic layer alpha.

## Prerequisites

-   The semantic layer alpha enabled for your organization
-   The [PostHog MCP server](/docs/model-context-protocol.md) connected to your agent (Claude Code, Cursor, Claude Desktop, or any MCP client)
-   An API key with the `data_catalog` scope – add `data_catalog_approval` too, since you'll approve a metric in this guide (see [governance](/docs/semantic-layer/governance.md#api-scopes) for why they're separate)
-   Some revenue-ish data in your [data warehouse](/docs/data-warehouse.md), like a synced `stripe_subscriptions` table

## Step 1: See the problem

Start by asking the question the way you would today:

> **You:** What's our MRR?
>
> **Agent:** There's no governed metric for MRR in your semantic layer, so I'll derive it myself. *Runs `execute-sql` over `stripe_subscriptions`...* Summing active subscription amounts, your MRR is **$142,300**. Note that this is a **noncanonical** number – I picked the tables and the definition myself, and a different session might pick differently.

That last sentence is the problem. Ask again tomorrow, in a different tool, or with slightly different wording, and the agent might exclude trials, include one-time charges, or use a different table entirely.

## Step 2: Propose the metric

Instead of letting every session re-derive MRR, catalog it:

> **You:** Create a semantic layer metric named `mrr` for monthly recurring revenue: the sum of active subscription amounts in `stripe_subscriptions`, in USD.
>
> **Agent:** *Calls `data-catalog-metric-create`...* Created the metric `mrr` with status `proposed`. It's recorded as AI-generated, with my model, confidence, and reasoning attached so a reviewer can see how I built it. It won't be treated as canonical until a human approves it.

The metric now exists, but it has no authority yet. Every AI-created object in the catalog lands as `proposed` – that's the "AI generates" half of the model.

**Names are write-once**

A metric's `name` is an identifier, like an API route: lowercase, no spaces, unique in your project. It can never be renamed or reused – even after deletion, the name stays reserved so a stored reference never silently changes meaning. Pick `mrr`, not `monthly_recurring_revenue_v2_final`. The `display_name` is the human label and stays editable.

## Step 3: Review and approve

Now the "a human owns" half. Look at what the agent proposed before you sign it:

> **You:** Show me the compiled query for the `mrr` metric.
>
> **Agent:** *Calls `data-catalog-metric-run`...* Here's the compiled HogQL – it sums `amount` over `stripe_subscriptions` where the subscription status is active. The response includes a `posthog_url` deep link if you want to inspect or tweak it in the SQL editor.
>
> **You:** Looks right. Approve the `mrr` metric.
>
> **Agent:** *Calls `data-catalog-metric-approve`.* About to approve metric 'mrr' as a canonical, human-vouched metric. Reply 'confirm' to proceed.
>
> **You:** confirm
>
> **Agent:** Done – `mrr` is now `approved`.

The typed "confirm" is deliberate: it's the human signature that makes a metric canonical, and an agent can't autocomplete it. Approval also requires the `data_catalog_approval` scope, so a key without it can propose but never promote.

## Step 4: Use it everywhere

Open a new session – or a completely different MCP client – and ask a real question:

> **You:** What was MRR last quarter, month by month?
>
> **Agent:** *Searches `system.information_schema.metrics`, finds one approved, non-drifted match: `mrr`. Calls `data-catalog-metric-run` with `date_from`, `date_to`, and a monthly `interval`.* Using your governed `mrr` metric: April **$128,400**, May **$135,100**, June **$142,300**. This is the canonical definition, approved by you – and here's the `posthog_url` deep link if you want to open the exact query in PostHog.

This is the payoff. The agent didn't reinvent MRR – it found the approved metric, ran it with your date range, and labeled the result canonical. Every session, every tool, every teammate now gets the same answer, and the [deep link](/docs/semantic-layer/metrics.md#running-a-metric) lets anyone audit exactly what ran.

## What you built

One conversation gave you the full trust chain:

1.  **AI proposed** – the agent drafted `mrr` and recorded its reasoning
2.  **You approved** – with a typed "confirm" that only a human can give
3.  **Everyone consumes** – every agent session routes MRR questions through the one governed definition

From here:

-   [Metrics](/docs/semantic-layer/metrics.md) – definition kinds, the lifecycle, and what happens when a metric drifts
-   [Certifications and relationships](/docs/semantic-layer/certifications-and-relationships.md) – govern the tables your answers come from, not just the answers
-   [MCP tools](/docs/semantic-layer/mcp-tools.md) – the full tool reference and more example prompts

### Community questions

Ask a question

### Was this page useful?

HelpfulCould be better