For the complete documentation index, see llms.txt. This page is also available as Markdown.

Entity YAML

Entity YAML files define the features, metrics, join rules, and examples for a single business entity.

First time here? If you haven't read the other file-type docs yet, start with knowledge-md.md to understand the scoping model, then task-instructions-md.md for SQL guidance patterns — both are shorter and establish context this file builds on. Come back here when you're ready to model entities.


Quick Reference — Feature Types

Type
What it does
When to use

field

Pulls a column directly from a source table

Any direct attribute — name, status, amount

metric

Aggregates from a related entity (feature chaining)

Per-entity totals — total revenue, order count

first_last

Gets the first or last value ordered by another field

Most recent plan, first order date

formula

Derives a value from other features on the same entity

Ratios, tiers, days-since calculations

Each type is documented in detail below.


Top-Level Structure

name: {entity_name}
description: {one or two sentence description}

key_source: {warehouse_table}    # primary table — defines entity identity
keys:                            # fields that uniquely identify a row
  - {field_name}

features:                        # attributes — see Feature Types below
  - ...

metrics:                         # aggregation logic — see Entity Metrics below
  - ...

related_sources:                 # secondary warehouse tables joined to the key_source
  {table_name}:
    ...

examples:                        # entity-level query examples
  - ...
Field
Required
Description

name

Yes

Entity identifier — referenced in queries as FROM <name>

description

Yes

Human-readable summary for agent context

key_source

Yes

The primary warehouse table (schema.db.table format)

keys

Yes

List of fields that form the primary key

features

Yes

List of feature definitions

metrics

No

List of entity metric definitions

related_sources

No

Secondary tables for enrichment

examples

No

Entity-scoped query examples


Name and Description

When a user asks a question, the agent decides which entities are relevant based on their name and description. These are the two fields the agent reads first — before looking at features or metrics.

name is the entity identifier. It appears in queries (FROM order), in relationships, and in metric feature references. Keep it short, lowercase, and unambiguous.

description is what the agent uses to decide whether this entity is relevant to the question. A vague description means the agent may miss the entity entirely or pick the wrong one. A good description answers:

  • What does this entity represent?

  • What questions or topics is it used for?

If your project has multiple entities that could answer similar questions (e.g., order and order_item), the description is how the agent chooses between them. Be explicit about what the entity represents and what questions it answers.


The source Field

Every feature (except formula) has a source field that tells the agent where to get the data. source always means "where this data comes from" — it can be a warehouse table or an entity.

Feature type

source can be

Format

field

A warehouse table/view or an entity

schema.db.table or entity name

first_last

A warehouse table/view or an entity

schema.db.table or entity name

metric

An entity only

entity name (e.g., order)

formula

No source — references features on this entity

metric features require an entity as source because they need aggregation logic (metrics:) that only exists on entities, not on raw tables.

When source is an entity (for field and first_last features), the join between the two entities must be defined in entities_relationships.yml. Specify which join to use with join_name if more than one join exists for that entity pair.


Feature Types

field — Direct Column

Pulls a column from a source without aggregation. A source can be one of two things:

  1. A warehouse table or view where each row on this entity maps to at most one source row. For example: enriching the customer entity with customer_last_signup_date from a warehouse table that is not the customer's key_source.

  2. A Lynk entity where each row on this entity maps to at most one source row. For example: enriching the order entity with the customer name from the customer entity (each order has exactly one customer).

Field
Description

name

Feature name — what users see and query

data_type

string, number, boolean, datetime

source

Where the field comes from. Either a warehouse table (schema.db.table) or an entity name.

field

The column name in the source table (may differ from name)

join_name

Which join to use. For a related_source table, the join defined on that source; for an entity source, a named join on the relationship. Omit (or set null) to use the default.

filters

Pre-filters applied to the source before retrieving the field. Omit if no filters.


Pulls an aggregated value from a metric defined on a related entity. This is feature chaining.

Field
Description

source

The related entity whose metric to use. Must be an entity name (e.g., order), not a raw table name — metric: is only defined on entities.

metric

The metric name from the related entity's metrics: section

join_name

Which relationship join to use. Omit to use the default join for this entity pair.

filters

Pre-filters applied to the related entity before aggregating. Use a sql expression with {source}.{field_name} references. Omit if no filters.

For the full mechanic — feature chaining, filtered metric features, which join is used, and metric-over-metric composition — see Metrics.


first_last — First or Last Value from a Source

Retrieves the first or last value from a set of rows, ordered by a specified field. Useful for "most recent plan", "first order date", "signup source".

Option
Description

method

first = smallest sort value; last = largest sort value

sort_by

The field to order rows by before selecting

field

The field to return from that row

offset

Optional. Which position to take — 1 returns the first/last row, 2 returns the second-from-first/last, etc. Defaults to 1 if omitted.


formula — Derived Value

Computes a value from other features on the same entity. References other features using {feature_name} syntax.

Formula features can reference any feature on the same entity — field, first_last, formula, or metric. They cannot reference features on other entities.


Entity Metrics

Entity metrics define how to aggregate rows of this entity. They are the targets of metric features on other entities.

Field
Description

name

Metric identifier — referenced by METRIC('name') in queries

description

Explains what it measures and how to use it

sql

Aggregation expression. References entity features with {feature_name} and can reference other metrics on the same entity via METRIC('name') (metric-over-metric composition). See Metrics for the full list of allowed patterns and dialect notes.

Entities are the source of truth. Raw warehouse tables are inputs — they exist to enrich entities, not to be queried directly. Metrics are defined on entities because entities are where business meaning lives. A raw table has columns; an entity has features, definitions, and metrics that the agent can reason about.

If you need a metric on data that currently lives only in a raw table, you have two options:

  1. Create a new entity from that table — if the table's level of granularity doesn't exist as an entity yet. Define the entity, bring in the fields as features, and add the metric there.

  2. Use an existing entity — if an entity already exists at the same level of granularity, create a relationship between that entity and the raw table, bring the fields in as features via related_sources, and define the metric as a rollup on those features.

In both cases, the metric ends up on an entity — which is the only place the agent can find and use it.

For what's allowed inside a metric's sql: — including conditional aggregation, dialect-specific constructs, and metric-over-metric composition via METRIC('name') — see Metrics.


A related_source is a secondary warehouse table bolted onto an entity to enrich it with additional columns. The table is not an entity itself — it feeds columns into one. Each entry in related_sources: defines the join from the entity's key_source to the secondary table.

Why define one:

  • Pull dimension or lookup columns from a separate table (e.g. a country name from a country reference table).

  • Enrich an entity with CRM, billing, or third-party columns that don't warrant their own entity.

  • Bring in flat reference tables (mapping tables, code-to-label lookups) whose rows have no independent business meaning.

What features you can build from a related_source:

Feature type
Supported
Why

field

Yes

Pulls a single column through the defined join

first_last

Yes

Picks one row from the related table ordered by a field

metric

No

Aggregations require the data to live in an entity — promote the table to an entity instead

formula

No

Formulas reference features on the same entity, never tables

If you need to count, sum, or average rows from this table, do not use related_sources — promote it to an entity.

Entity vs. related_source — the granularity test:

The decision rule above is about features. This one is about the table itself: what level of granularity does this table represent? Create a new entity if the table represents a business concept at its own level of granularity (something you'd ask questions about on its own — e.g. order, subscription, session) or if other entities need to relate to it via the relationship graph. Otherwise — if it's flat enrichment with no independent business meaning — use related_sources.

How to pick the key_source for an entity:

A table is the right key_source for an entity if it contains all instances of the concept and each instance appears exactly once. For a customer entity, the customers table where every customer has exactly one row is the right key_source. Other tables at the same customer level (e.g., a CRM enrichment table with one row per customer) connect as related_sources. Tables at a finer granularity (e.g., orders, one row per order per customer) connect as relationships — they can be aggregated up to the customer level via metric features.

Join types for related_sources:

Type
Description

sql

Explicit SQL join condition using {source} and {destination}

lookup

Multi-hop join through intermediate tables


When to Use This File

Create or update an entity YAML file when a concept meets one of these conditions:

  1. You're modeling a new business concept the agent should be able to query

  2. You're adding or changing a metric, feature, or dimension on an existing entity

  3. The agent produces wrong results for a specific entity — field choices, joins, or calculations need fixing

Examples:

  • "We want the agent to answer questions about orders — revenue, volume, channel performance" → create an order entity

  • "Users keep asking about customer health but there's no entity for it yet — model customer with ARR, NPS, and churn status" → create a customer entity

  • "Add a new metric to customer — total revenue from the last 90 days" → add a filtered metric feature to the existing entity

  • "The agent is joining the wrong table for revenue questions — there are two revenue fields and it keeps picking the wrong one" → add entity-level task instructions and improve feature descriptions

  • "We onboarded a new data source for product usage — model it as a session entity so the agent can answer engagement questions" → create a new entity from the source table


Best Practices

Write descriptions that tell the agent when to use this entity. The agent selects entities based on name and description — a vague description means missed or wrong matches. Answer: what does this entity represent, and what questions should it answer?

Write feature descriptions that tell the agent when to use a field. When two date fields exist on an entity (e.g., created_at and completed_at), the description should state which one to use for filtering — for example, "use this for all date filtering, not created_at".

Define entity metrics before referencing them in metric features on other entities. Metric features on customer that reference order metrics depend on those metrics being defined on the order entity. Build the source entity first.

Prefer metric features for cross-entity aggregation. If you need a per-customer revenue total, define it as a metric feature — not a formula that approximates it. Metric features use the relationship join; formulas do not.

Use first_last for single values from a many-side entity. If you need "most recent order date" on customer, use first_last — not a formula. Formulas cannot aggregate across rows.

Keep key_source as the primary grain table. Enrichment from secondary tables belongs in related_sources. The key_source defines the entity's identity — one row = one entity instance.


Common Pitfalls

Using a raw table name in a metric feature's source

Defining metrics on related_sources Sources cannot have metrics. If you need to aggregate from a source, create an entity whose key_source is that table, define the metrics on the entity, then use a metric feature.

Circular formula references Formula features can only reference features that are already computed at the same level. A formula cannot reference another formula that references it back.

Missing relationship for a metric feature Metric features require a relationship between the two entities in entities_relationships.yml. If the relationship does not exist, the metric feature cannot be resolved.

Defining entity aliases in the entity YAML Aliases — the different names business users use to refer to an entity — belong in the entity knowledge file, not here. The entity YAML defines schema, features, and metrics. The knowledge file is where the agent learns how users naturally refer to this entity in questions.

Using {feature_name} curly braces in the examples: section's expected_output Curly-brace {feature_name} is required in feature-definition SQL — formula sql:, entity-metric sql:, metric/first_last filter sql:, and join sql: — because Lynk resolves those references at compile time. But the examples: section's expected_output is a Lynk SQL query, not feature-definition SQL, so features are referenced by name without braces. See Lynk SQL for the full query-side rules.

Putting filtering rules, SQL instructions, or cross-entity references in the entity description The description field is for what the entity represents and what questions it answers — nothing more. Filtering rules like "always exclude is_inactive = true" belong in task instructions. Cross-entity pointers like "use the player entity for career aggregates" don't belong here either — the agent selects entities based on question relevance, not navigation hints embedded in descriptions.


Full Examples

These examples cover three different companies. Example 1 is Grove (B2B SaaS) — the customer entity, which uses metric features to pull subscription data from the subscription entity. Example 2 is Bly (e-commerce) — the order entity, standalone with its own metrics. Example 3 is Arcadia (mobile gaming) — the player entity, which uses metric features from purchase and formula-based segmentation. Reading all three shows the same pattern — entity metrics → feature chaining → query examples — in three distinct business contexts.


Example 1 — Grove (B2B SaaS), customer entity

The customer entity includes metric features from the subscription entity (active subscription count and total MRR). The customer-subscription relationship must be defined in entities_relationships.yml for these features to resolve.


Example 2 — Bly (E-commerce), order entity

The order entity is standalone — all metrics are computed directly from order-level features. Note that order_date is the time field, not created_at.


Example 3 — Arcadia (Mobile gaming), player entity

This example shows formula-based segmentation (player_segment derived from rolling 30-day spend), two metric features from purchase (lifetime and filtered), and a MEDIUM query that identifies high-value players at churn risk. The player-purchase relationship must be defined in entities_relationships.yml for the metric features to resolve.

Last updated