Skip to main content
Glama

patrol_dbt

Checks a dbt model's table for data-quality incidents across daily partitions, tests proposed fixes against control totals, and reports which are safe to auto-fix or need escalation.

Instructions

Check the table behind a dbt model for data-quality incidents and say which are safe to fix.

A patrol checks every daily partition of the fact table for duplicate keys, duplicate rows, missing
partitions, rows that point to no reference record, null spikes, and row counts or amounts that do not
match the source's control totals. For each problem it proposes a fix, tests that fix on a copy against
the control totals, and decides: "auto-fixed" (proven and low risk), "no action needed" (checked, the
data is right) or "escalate" (a person must decide).

Use this after `dbt build` or `dbt run`, before trusting or publishing a date-partitioned model. It
finds the model's table from dbt's manifest, connects the way the project's profile says (DuckDB and
Snowflake targets are supported), and takes the column mapping from the model's `meta: dataranger:`
block unless you pass columns here. Use patrol_snowflake or patrol_duckdb for tables that are not dbt
models, and patrol_files for CSV or Parquet exports.

Behavior: reads target/manifest.json, dbt_project.yml and profiles.yml; it does not run dbt. It then
runs three SELECT statements and nothing else, so neither the warehouse nor the dbt project is
modified. On Snowflake it selects only the mapped columns for the last `days` days. The only side
effect is writing four report files to out_dir: dashboard.html, audit.jsonl, incidents.csv and
fixed_version.csv (the proposed corrected table, for review). Fails with a readable error if the
manifest is missing (run dbt first), a model is unknown, the target type is not supported, or a
mapped column does not exist.

Returns the counts (incidents, auto_fixed, no_action_needed, escalate), needs_a_person (the escalated
incidents), all_incidents (partition, problems, decision, proposed_fix, residual for each) and
outputs (paths to the report files). Pass outputs.folder and a partition to get_incident for the
full evidence behind one decision. Tell the user about every escalated incident.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "project_dir": "<project_dir>",
      "model": "<model>"
    },
    "name": "patrol_dbt"
  }
}

Input Schema

NameRequiredDescriptionDefault
keyNoPrimary key column of the fact model. Omit to use meta.dataranger.key, or txn_id.
dateNoDate column the fact model is partitioned by; the control totals need the same column. Omit to use meta.dataranger.date, or txn_date.
daysNoRead only the last N days of the fact table and control totals (today counts as day one). Use at least 30 so the checks have a baseline. Pass null to read the whole table, which can be slow and costly.
modelYesName of the dbt fact model to check, for example fct_payments. A seed, snapshot, or a source written as source_name.table_name also works.
amountNoNumeric amount column of the fact model. Omit to use meta.dataranger.amount, or amount.
targetNodbt target to read from, for example prod. Omit for the profile's default target.
out_dirNoFolder to write the report files into. Created if missing; report files already there are overwritten. Omit to use a new temporary folder; its path comes back in outputs.folder.
ref_keyNoKey column of the reference model. Omit to use meta.dataranger.ref_key, or customer_id.
segmentNoColumn that splits each day into segments, such as channel; the control totals need the same column. Omit to use meta.dataranger.segment, or channel.
categoryNoOptional categorical column of the fact model. Omit to use meta.dataranger.category, or none.
ref_modelNodbt model of the reference table that fact rows point to, for example dim_customers. Omit if the fact model's meta.dataranger block sets ref_model.
referenceNoFact column that points to the reference model. Omit to use meta.dataranger.reference, or customer_id.
thresholdNoGate threshold: the largest relative gap to the control totals that a verified fix may leave and still be marked auto-fixed (0.01 = 1%). Lower is stricter. Omit for the benchmark-calibrated default, 0.0135.
project_dirYesPath to the dbt project folder, the one that holds dbt_project.yml. It must have been built or parsed, so target/manifest.json exists.
profiles_dirNoFolder that holds profiles.yml. Omit to look in DBT_PROFILES_DIR, the project folder, then ~/.dbt.
manifest_modelNodbt model holding the source system's control totals: one row per date and segment ('*' = whole day) with n and amount. Omit if the fact model's meta.dataranger block sets manifest_model.

Output Schema

NameRequiredDescriptionDefault
noteYes
tableYes
outputsYes
escalateYes
incidentsYes
auto_fixedYes
rows_checkedYes
all_incidentsYes
gate_thresholdYes
needs_a_personYes
no_action_neededYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv0.5.1

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it names the files read (target/manifest.json, dbt_project.yml, profiles.yml), states dbt is not executed, bounds the warehouse activity to three SELECTs, and pinpoints the only side effect — four named report files written to out_dir, which are overwritten if present. It also lists the concrete failure modes (missing manifest, unknown model, unsupported target, missing mapped column), which the openWorldHint annotation alone would not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then a clearly labeled 'Behavior:' block and a 'Returns' block, so an agent can skim to what it needs. The returns paragraph partly restates output that the output schema already carries, and the middle paragraph is dense with fallback paths, but the closing instruction to surface escalations earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter, multi-source tool with a true output schema, the description covers the pieces that matter: where column mappings come from, what is read versus executed, what is written and where, and how failures surface. Return values are summarized just enough to route to get_incident without duplicating the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3; the description earns above that by explaining the meta.dataranger resolution order for the column-mapping parameters (key, date, amount, reference, ref_model), which is override logic the schema does not spell out. Minor gap: it does not discuss threshold or target beyond what the schema fields already say.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — check the table behind a dbt model for data-quality incidents and classify what is safe to fix — and enumerates the concrete checks (duplicate keys, missing partitions, orphan rows, null spikes, control-total mismatches). The final routing sentence separates it from patrol_snowflake, patrol_duckdb and patrol_files by table type, so an agent can pick correctly without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('after dbt build or dbt run, before trusting or publishing a date-partitioned model') and names each alternative plus the exact condition that selects it: patrol_snowflake/patrol_duckdb for non-dbt tables, patrol_files for CSV/Parquet exports. It also directs the caller onward to get_incident for per-decision evidence.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.