Metrics
A metric is defined once, in a file in git, with a description that tells an agent when to use it. Reports, the API and the MCP connector all read that one definition, so two people asking for “net sales” get the same number.
The e-commerce template has 115 metrics across 8 datasets, each defined this way.
The semantic layer
Section titled “The semantic layer”The semantic layer lives in anfra, the engine from Holistics. You write it in AML files under semantic/ in your project:
models/*.model.amlmap a table the transform step built.datasets/*.dataset.amlgroup models with their dimensions and metrics. A dimension is a field you group or filter by, such aschannel. A metric is a number you compute, such as total net sales.apps/holds reports.
One definition per metric
Section titled “One definition per metric”Each metric has one key, one definition and one description. The key is a name like total_net_sales_excl_vat. Its definition is a formula in anfra’s query language, AQL:
definition: @aql fct_orders_base__order_lines.total_net_sales_excl_vat ;;If two reports need a number that differs in what it counts, that is two metrics with two names. A period comparison is not a metric. Year over year and month over month are the same calculation on a shifted period, which anfra does when it runs the query.
The description is the guidance
Section titled “The description is the guidance”AML has no field for aliases or for when to use a metric. So the description holds them, in a fixed shape. The first sentence says what the number is. Then come these labelled sections:
| Section | What it answers |
|---|---|
| Aliases | Other names people use for it, so search finds it |
| When to use | The question it fits, and which metric to use for a nearby question |
| Not the same as | The metrics it is often confused with, and how they differ |
| Grain and filters | What one row is, and what is left out |
| Sample questions | Questions a person might ask that it answers |
| Caveats | When the number misleads |
mb check refuses a metric with no first sentence, no Aliases (it may say none), no When to use, no Grain and filters, or no unit: tag. It also requires Not the same as when another metric shares a word of the label.
Here is the real description of total_net_sales_excl_vat in the template. This copy is shortened: the real one lists more look-alike metrics under Not the same as.
metric total_net_sales_excl_vat { label: 'Total net sales excl VAT' description: ''' What customers paid for the items they bought, after sale prices and discounts and less the money paid back for them.
**Aliases:** net_sales, Net sales, Net revenue, Revenue **When to use:** To see how much the shop sold. For what customers paid at checkout, shipping and VAT included, use Total order value incl VAT. **Not the same as:** Total gross sales excl VAT, which is at list price before discounts and refunds. **Grain and filters:** One sold item, on the day its order was placed. Gift cards, cancelled orders and test orders left out. Shipping and VAT excluded. **Sample questions:** How much did we sell last month? Which sales channel sold the most? **Caveats:** Refunds keep arriving for weeks, so the latest weeks read high until they do. '''}An agent reads these sections to pick the right metric and to say what a number includes. The Caveats line is why it can warn that last week’s net sales will still fall.
Metric names
Section titled “Metric names”A key says what kind of number it is, then what it counts, then its qualifiers. The label is the key in words, in sentence case.
| Kind | Form | Example |
|---|---|---|
| count | number_of_<objects> |
number_of_orders |
| sum | total_<amount> |
total_net_sales_excl_vat |
| mean | average_<thing>[_per_<unit>] |
average_number_of_items_per_order |
| rate | <event>_rate[_<base>] |
return_rate_items |
Qualifiers come in a fixed order: deduction stage, basis, unit, then VAT. Every money metric ends in _excl_vat or _incl_vat. Use business words, and put abbreviations such as AOV in Aliases. The full rules are in docs/standards/naming.md in the core repository.
A term is a business word with one meaning, such as “Cancelled order”. Most terms are a dimension. “Cancelled order” is the boolean is_cancelled_order. You write its definition on the dimension, next to the logic. A concept with no field behind it, such as a cohort, goes in a file terms/<term_name>.md in your project. The glossary shows both together.
Reports
Section titled “Reports”A report is one HTML file under semantic/apps/. The web app hosts it. Every query a report makes passes the same access check as any other query, so opening a report never gives its viewer data they could not query. See Security.
Definitions change only in git
Section titled “Definitions change only in git”No tool writes a definition. The API and the connector read and query. To add or change a metric, your agent edits the files and opens a pull request. A person reviews and merges it. The history of every number is the git log.
See Built for agents for how an agent works with these files.