DBDelve
Dive deep into your data. A fast, native, multi-engine database client written in Rust. Free and open source, no telemetry.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Reliable AI lead routing: dbt business context, deterministic routing policy, a workflow ledger for safe retries, and read-only MCP tools for Claude. Runnable on synthetic data.
翻訳待ち
Loading the full README.
Read the full README ↗A small, runnable example of AI-assisted lead routing. dbt prepares the business context, plain Python applies the routing policy, a ledger tracks workflow state so retries are safe, and an MCP server gives Claude (or any MCP host) read-only tools to inspect leads and explain decisions.
The model never picks the owner. It reads context, explains the rule that fired, and can suggest a missing value, and every suggestion goes to a human.
Status: educational prototype. It runs locally on synthetic data. There is no real CRM connection, no authentication and no multi-worker concurrency. See What this does not do.
A new lead arrives. The company looks enterprise-sized, but it might already be a customer. There could be an open opportunity with an owner. The country field is blank, and the same person signed up last week with a slightly different email format.
You can ask an LLM "who should own this lead?" and get a plausible answer. What you won't get is the same answer every time, a rule you can point to, protection against assigning the same lead twice, or a record of why. Those come from the system around the model.
This repo splits the job up:
| Layer | Tool here | Job |
|---|---|---|
| Business context | dbt + DuckDB | Normalize emails, domains, countries and sizes. Join accounts, open opportunities and territories. Flag missing fields and duplicates. One row per lead. |
| Decision | Python (policy.py) | Ordered, versioned rules. Returns rule_id, reason and evidence for every decision. No I/O, no model calls. |
| Workflow state | SQLite ledger (workflow.py) | One case per lead, input fingerprint and policy version. Approvals, retries and an audit trail. |
| Assistance | MCP server (mcp_server.py) | Six read-only tools: list, inspect context, preview, preview with a model-suggested country, inspect a case, explain the policy. |
| Side effects | Fake CRM (crm_stub.py) | Idempotent owner writes, with simulated outages and lost responses so you can watch retries work. |
You need Python 3.11+ and git. No API keys or accounts are required.
git clone https://github.com/meerkatsai/lead-routing-context-demo.git
cd lead-routing-context-demo
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Build the context model. This loads the synthetic CSVs, builds lead_routing_base and runs 16 dbt data tests:
lead-routing build
Done. PASS=26 WARN=0 ERROR=0 SKIP=0 NO-OP=0 REUSED=0 TOTAL=26
Check every lead against the expected outcomes in data/expected_outcomes.csv:
lead-routing eval
lead_id expected got match
------- ---------------------------------------- ---------------------------------------- -----
L-001 TERRITORY_OWNER -> own_maya TERRITORY_OWNER -> own_maya yes
L-002 EXISTING_ACCOUNT_OWNER -> own_oliver EXISTING_ACCOUNT_OWNER -> own_oliver yes
L-003 EXISTING_ACCOUNT_OWNER -> own_maya EXISTING_ACCOUNT_OWNER -> own_maya yes
L-004 EXISTING_OWNER_MISSING -> revops_review EXISTING_OWNER_MISSING -> revops_review yes
L-005 OWNER_CONFLICT -> revops_review OWNER_CONFLICT -> revops_review yes
...
L-015 EXISTING_ACCOUNT_OWNER -> own_priya EXISTING_ACCOUNT_OWNER -> own_priya yes
accuracy 15/15 false assignments 0 review rate 33%
Run the test suite (it builds its own copy of the warehouse in a temp folder):
pytest
52 passed
Route every lead and record a case for each:
lead-routing route-all
lead_id rule_id destination case_status case_id ledger
------- ---------------------- ---------------- --------------- ----------------- --------
L-001 TERRITORY_OWNER own_maya previewed case_46357e2fb198 new case
L-002 EXISTING_ACCOUNT_OWNER own_oliver previewed case_0b6eb8e9692e new case
L-004 EXISTING_OWNER_MISSING revops_review review_required case_417e5b342370 new case
L-005 OWNER_CONFLICT revops_review review_required case_4eb2824a5b42 new case
L-012 DUPLICATE_LEAD L-001 duplicate case_bb1ddc8fc342 new case
...
Run it again, or rebuild dbt and run it again. Every row now says existing case, because the input fingerprint and policy version haven't changed. Your case IDs will differ from the ones shown here.
Look at one decision:
lead-routing preview L-003
{
"lead_id": "L-003",
"status": "assigned",
"queue_or_owner": "own_maya",
"rule_id": "EXISTING_ACCOUNT_OWNER",
"reason": "Kept the owner of the existing account/opportunity",
"needs_review": false,
"policy_version": "v1",
"evidence": {
"account_id": "A-102",
"is_existing_customer": false,
"account_owner_id": "own_maya",
"open_opportunity_ids": ["O-500"],
"open_opportunity_owner_ids": ["own_maya"]
},
"data_quality_flags": []
}
L-003 has no country, so a territory rule can't run. The open opportunity already has an owner, and that rule comes first, so the owner is kept.
This is the beginning of the README. Read the rest at the original. Read the full README ↗