A dataset gate for LLM / RAG / analytics pipelines. It profiles a tabular dataset (CSV / JSONL / JSON), checks it against declarative rules and an optional baseline profile, then returns a machine-readable verdict — and a non-zero exit code when the data is bad enough to stop the pipeline.
The promise (and its limits)
Most pipeline incidents are not code bugs: an upstream extract silently returns 0 rows,
a column is renamed, a NULL rate triples, prices arrive in cents instead of euros. The
job downstream keeps running and quietly trains, indexes or bills on garbage.
This agent puts a gate in front of that job:
- It blocks on hard breaches: missing required column, wrong type, duplicate primary key, out-of-range value, empty extract, stale data.
- It warns on drift against a baseline: null-rate jumps, numeric mean shifts.
- It explains — if you connect a coding-agent CLI — why the data broke and which rule change is safe, via the Analyst prompt.
What it is not: a data catalog, a lineage tracker, or a transformation engine. It does not fix your data. It refuses to let bad data through and tells you what happened.
Who it is for
Anyone running a scheduled job over data they do not control: RAG ingestion, nightly analytics loads, ETL into a warehouse, billing exports, ML retraining.
Quick start
./install.sh # one-shot Debian install
python3 agent.py --help
# 1. Learn what "normal" looks like
python3 agent.py profile --input samples/orders_clean.csv --out baseline.json
# 2. Gate a dataset (exit code 1 = BLOCK)
python3 agent.py check --input samples/orders_broken.csv --rules rules.json
echo "exit code: $?"
# 3. Explain the failure (uses your LLM CLI if connected, deterministic otherwise)
python3 agent.py triage --report reports/latest.json
Use it in CI or cron exactly as you would any other gate:
python3 agent.py check --input daily_export.csv || exit 1 # pipeline stops here
Architecture
┌─────────────┐
│ dataset │ CSV / JSONL / JSON
└──────┬──────┘
│
┌──────▼──────┐ rules.json ┌──────────────┐
│ profile │◄────────────────────│ baseline │
│ (no LLM) │ │ (optional) │
└──────┬──────┘ └──────────────┘
│ column stats, null rates, types
┌──────▼──────┐
│ check │ deterministic rules + drift
│ (no LLM) │
└──────┬──────┘
│ findings[] {rule, severity, message}
┌──────▼──────┐
│ verdict │ PASS → 0 WARN → 0 BLOCK → 1
└──────┬──────┘
│ reports/latest.json
┌──────▼──────┐
│ triage │ BYO-LLM: root cause + safe rule fixes
│ (optional) │ falls back to deterministic summary
└─────────────┘
The gate is deterministic end to end. The LLM only ever explains a report that was already produced without it — so a missing CLI, a rate limit or an offline box degrades the agent to "still blocks bad data, just less chatty".
Contents
| File | Role |
|---|---|
agent.py |
Entrypoint: profile, check, triage, run, status. |
rules.json |
Declarative rules (edit this first). |
llm_adapter.py |
Bring-your-own-LLM CLI adapter. No API key stored. |
PROMPTS.md |
Analyst + Executor prompts, loaded at runtime. |
SPEC.md |
Every rule, env var, exit code and report field. |
CUSTOMIZE.md |
Where to plug your own datasets, rules and prompts. |
CHECKLIST.md |
Deployment checklist, ~25 steps. |
SOUL.md |
Mission, values, OODA states. |
test_agent.py, smoke_test.sh |
Offline test suite — no network, no key. |
install.sh, deploy.sh, *.service |
One-shot Debian install + systemd unit. |
Verdicts
| Verdict | Meaning | Exit code |
|---|---|---|
PASS |
No finding. | 0 |
WARN |
Drift or soft breach; pipeline may continue. | 0 (1 with --fail-on warn) |
BLOCK |
Hard rule breach. | 1 |
Bring your own LLM
No API key ships with this pack and none is required. If a coding-agent CLI
(Claude Code / Kimi Code / Codex) is on PATH, triage uses it. Otherwise every command
still runs — see CUSTOMIZE.md.
Test offline
./smoke_test.sh # deterministic, no network, no key