Kaelio/ktx is a context layer that helps AI agents query analytical databases using company knowledge, approved metrics, table metadata, and relationships between columns. Data teams use it to make warehouse queries more accurate and consistent with their organization's definitions. Its catalogue add-ons teach agents how to use ktx and its data-querying interfaces.
Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add Kaelio/ktx --skill metricflow_ingestgit clone --depth 1 https://github.com/Kaelio/ktxWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/kaelio/ktx/metricflow_ingest)<a href="https://agentmods.dev/skills/kaelio/ktx/metricflow_ingest"><img src="https://agentmods.dev/badge/skills/kaelio/ktx/metricflow_ingest/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/kaelio/ktx/metricflow_ingest"><img src="https://agentmods.dev/badge/skills/kaelio/ktx/metricflow_ingest.svg" alt="Reviewed on agentmods" width="80" height="20"></a>- NVIDIA SkillSpector warn
SkillSpector: 1 finding, up to high
These are SkillSpector’s own severities. On a checked sample its high-severity flags on skills were ~96% false positives — a documented command, a public API, a “never do X” rule — so we show them as a caution to read, not a verdict. Why →
- high Prompt Injection · line 153 Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.Fix: Audit all comments and invisible characters. Remove any instructions that direct the agent to perform unauthorized actions. Use plain, reviewable content.
What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00000 | $0.03907 |
| Opus 5 | $0.00000 | $0.01954 |
| Sonnet 5 | $0.00000 | $0.00781 |
| Haiku 4.5 | $0.00000 | $0.00391 |
Grade A, and why
metricflow_ingest scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 10d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 314 lines — stays where its author put it; the contents beside it link to each section on GitHub.
MetricFlow to ktx Semantic Layer
A MetricFlow semantic_model maps to an SL source; MetricFlow measures map to ktx measures; MetricFlow entities map to ktx joins; MetricFlow metrics (top-level) map to ktx measures OR to cross-model derived measures. Files in one WorkUnit are ALWAYS part of the same logical entity (a connected component, possibly spanning extends: + cross-model metric refs). Flatten inheritance and cross-file references at write time.
Mapping table
| MetricFlow | ktx form | Notes |
|---|---|---|
semantic_model: X { model: ref('t') } with measures + dimensions |
Overlay named X with measures, computed-only columns, column_overrides, joins |
The model: ref resolves to a manifest table. |
semantic_model: X { model: source('s','t') } |
Overlay named X over table t. |
Same shape; source() still resolves to a physical table. |
semantic_model: X { model: <literal> } with no manifest entry |
Standalone with explicit sql:, grain:, columns: |
Happens when the dbt manifest isn't available. |
semantic_model: Y { extends: X } |
Merge Y's measures/dimensions/entities into X's overlay, or write a single overlay named for the most-derived child (Y) containing both X's and Y's primitives | Do not emit a second overlay for X - flatten. |
measures: [{ name, agg, expr }] |
measures: [{ name, expr: "<agg>(<expr>)" }] |
Aggregation inlined. agg: count_distinct → count(distinct ...). |
entities: [{ name, type: primary }] |
grain: [<entity_name-or-expr>] on the overlay/standalone |
Primary/unique entities drive grain. |
entities: [{ name, type: foreign }] |
joins: entry joining to the primary-entity's semantic_model |
Only when a matching primary is discoverable. |
metrics: [{ type: simple, type_params: { measure: X } }] |
If the base measure is labeled/described by the metric: in-place edit to the existing measure. Otherwise leave as-is. | Same-name metrics can absorb metadata. |
metrics: [{ type: simple, filter: <jinja> }] |
New measure on the same source, with the filter translated to SQL and attached via filter: |
Translate Jinja {{ Dimension('x__y') }} to the column name y. |
metrics: [{ type: derived, type_params: { expr, metrics } }] |
Derived measure on whichever source owns the referenced measures, with expr: referencing measure names |
If the metric spans models, still write it once on the source owning the "primary" measure (the one the agent judges most central). Mention the cross-model chain in the description. |
metrics: [{ type: ratio, type_params: { numerator, denominator } }] |
Same as derived; expr: "numerator / NULLIF(denominator, 0)" if no explicit expr |
Safe-division by default. |
metrics: [{ type: cumulative, type_params: { window, grain_to_date } }] |
Standalone source with a window-function SQL; reference the resulting column as a normal measure | ktx SL has no first-class cumulative primitive (spec Non-goals). |
metrics: [{ type: conversion }] |
Flag for human - do NOT write. Emit a wiki note describing the intended semantics. | No ktx equivalent in v1. |
| Metric not mappable | Wiki page <metric_name>-definition.md with the full YAML body quoted |
Capture the intent even if we can't emit SL. |
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 10d ago First seen · 314 lines · 0 tokens per session scan A 528912693ed0
metricflow_ingest is a skill published in the GitHub repository Kaelio/ktx (1,581 stars, last pushed 6d ago), licensed Apache-2.0. It costs nothing until one of its globs matches a file; then it loads 3,907 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
migrating-ai-sdk-to-common-ai
Migrates Airflow projects from airflow-ai-sdk to apache-airflow-providers-common-ai 0.4.0+. Use when replacing airflow-ai-sdk with the official Airflow AI provider - migrating LLM decorators (@task.llm, @task.agent, @task.llmbranch, @task.embed), switching from model strings/objects to connection-based LLM…
airflow
Queries, manages, and troubleshoots Apache Airflow using the af CLI. Use when working with anything related to Airflow - a DAG, a DAG run, a task log, an import or parse error, a broken DAG, or any Airflow operation. Covers listing and triggering DAGs, retrying runs, reading task logs, diagnosing failures, debugging…
cosmos-dbt-core
Turns a dbt Core project into an Airflow DAG/TaskGroup using Astronomer Cosmos. Use turning a dbt Core project into an Airflow DAG or TaskGroup with Astronomer Cosmos. Before implementing, verify dbt engine, warehouse, Airflow version, execution environment, DAG vs TaskGroup, and manifest availability.
creating-openlineage-extractors
Create custom OpenLineage extractors for Airflow operators. Use when the user needs lineage from unsupported or third-party operators, wants column-level lineage, or needs complex extraction logic beyond what inlets/outlets provide.
delegating-to-otto
Drives Astronomer's Otto agent (astro otto) as a delegated sub-agent for Airflow, dbt, and data-engineering work. Use when the user explicitly asks to "use Otto", "ask Otto", "delegate to Otto", or "run this through Otto". Also offer Otto for Airflow 2 → 3 migrations and upgrade planning even when not named — Otto's…
annotating-task-lineage
Annotate Airflow tasks with data lineage using inlets and outlets. Use when the user wants to add lineage metadata to tasks, specify input/output datasets, or enable lineage tracking for operators without built-in OpenLineage extraction.