Skip to main content
Layer: Semantic layer
Computes a pre-declared metric against the live database. Returns the materialised rows, the parameterised SQL the compiler emitted, and a fingerprint linking back to the immutable audit row. The agent never writes SQL itself for declared metrics — SchemaBrain compiles and parameter-binds.
{
  "rows": [
    {"group_col_0": "Enterprise", "active_subscriptions": 4},
    {"group_col_0": "Free", "active_subscriptions": 8},
    {"group_col_0": "Pro", "active_subscriptions": 2}
  ],
  "row_count": 3,
  "sql_skeleton": "SELECT \"plan\".\"title\" AS group_col_0, count(\"subscription\".\"id\") AS active_subscriptions FROM \"public\".\"subscriptions\" AS \"subscription\" JOIN \"public\".\"plans\" AS \"plan\" ON \"subscription\".\"plan_id\" = \"plan\".\"id\" GROUP BY group_col_0 ORDER BY group_col_0 ASC LIMIT :p_limit",
  "sql_params": {"p_limit": 1000},
  "fingerprint": "f3a1c89e...",
  "required_joins": ["subscription_plan"],
  "fan_out_join_names": [],
  "pii_categories": [],
  "token_estimate": 239
}
  • group_by and filters use entity.column form (e.g. plan.title, invoice.issued_at) — never physical schema.table.column.
  • filters is (column, op, value) with closed-set ops: eq, ne, lt, lte, gt, gte, in, not_in, is_null, not_null.
  • Values bind as parameters — never inlined into SQL.
  • fan_out_join_names flags joins where the cardinality could inflate rows. When the list is non-empty the envelope downgrades to status="degraded" with confidence="MEDIUM" — this is the machine-readable signal the agent should surface to the user, not the list itself.
  • pii_categories propagates the MAX-sensitivity + UNION-categories of every column touched, and is what --pii-block filters against.
Use list_entities instead when you don’t yet know what’s defined. get_metric only computes pre-declared metrics — it will never run arbitrary SQL.