Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
MCP server for entity resolution and golden records
GoldenMatch matches messy records into stable entities, then keeps the identity layer durable with field provenance, survivorship, merge/split, and audit history. The same engine is exposed through Python, TypeScript, SQL in Postgres and DuckDB, and an MCP server so agents can call it directly.
Builders who want their agent to resolve duplicate records and maintain a Customer 360 identity layer.
You can feed messy customer data into one system and get stable golden entities back with provenance and history.
What it does
Zero-config entity resolution
Profiles incoming data and deduplicates records without manual rules or training data.
Durable identity layer
Assigns stable entity IDs and keeps merge, split, survivorship, and audit history.
Customer 360 view
Returns a unified record with per-field provenance, source records, timeline, and relationships.
MCP and REST surfaces
Exposes the same capabilities through an MCP server and REST API for agent use.
Multi-language parity
Provides Python, TypeScript, and SQL surfaces with conformance-tested shared behavior.
Scale and benchmarks
Includes benchmarked Arrow-native and Rust-backed matching paths for large datasets.
How to get it
- 1Dedupe a CSV in 30 seconds, zero config, writes _golden.csv
pip install goldenmatch && goldenmatch dedupe customers.csv
- 2The whole suite, configured for speed. golden-suite pulls in every package plus the…
pip install golden-suite golden-suite doctor # verify every package + native kernel is importable and healthy golden-suite optimize # repair / re-enable the perf-optimized config pip install golden-suite[mcp] # + aggregator MCP server (every tool, one endpoint) pip install golden-suite[all] # everything
README
Golden Suite
Your customer data lives in a CRM, a billing system, and three spreadsheets nobody owns. Some records are duplicates. Some are the same company spelled four different ways. Nobody can answer how many customers do we actually have, and every dashboard built on top inherits the doubt.
Splink-beating entity resolution, Arrow-native and Rust-fast with zero tuning, feeding a durable identity layer so messy records from every source become stable golden entities with whole-record, Customer-360 provenance.
Zero-config matching that beats expert-tuned Splink head-to-head on messy customer records, in an Arrow-native, Rust-authoritative engine verified from a laptop CSV to a 250M-row dedupe in 11.2 minutes. The identities it produces live in a transaction-native control plane carrying stable entity_ids, per-field provenance, merge/split, and a tamper-evident audit log, all one call away as a Customer 360. It even owns its primitives: byte-identical, faster-than-rapidfuzz / jellyfish / FAISS Rust kernels, not rented dependencies.
Python · TypeScript · SQL, at 4-decimal parity · native in Postgres + DuckDB · edge WASM · 70+ MCP tools · beats hand-tuned Splink · 250M rows in 11.2 min
Pair drilldown in the web workbench: cluster members, field-level diff, and a one-line NL explanation per pair. pip install goldenmatch[web] then goldenmatch serve-ui <project>. More screenshots →
v3.17.1: The polars-free first run actually works now. 3.17.0 claimed this and did not deliver it: auto-config puts negative evidence on the exact matchkey by default, and that path still bridged to polars, so
goldenmatch dedupe customers.csvexited 3 on a default install. Verified the way it should have been the first time --pip installinto a clean polars-free venv, then the documented command.v3.17.0: The documented first run works on a default install.
pip install goldenmatchfollowed bygoldenmatch dedupe customers.csv-- the quickstart on every doc surface -- exited 3 on a polars-free install, which is what a plain install has produced since polars became an optional extra. Three separate polars imports on the zero-config path (auto-config ingest, the Arrow lane's preflight decline, and the csv writer) are gone, with polars' exact csv bytes reproduced and parity-pinned.v3.13.0: Fellegi-Sunter training runs distributed on Spark. The E-step reads only the comparison vector, so identical vectors collapse to one counted row and the whole step becomes a Spark
GROUP BYover agreement patterns -- the cluster counts, the driver only fits. Training cost tracks DISTINCT vectors (bounded byprod(levels + 1)), not pairs: 1M -> 5M rows grew candidate pairs 5.00x and the distributed counting stage 5.25x, while distinct patterns grew 3.0% (433 -> 446) and driver-side EM stayed at 0.01s. Runs on jar-only executors viagoldenmatch-spark, off the same Rust kernel every other surface uses.
What you get: the golden entity
Most entity-resolution tools hand you clusters and stop. GoldenMatch keeps going: it resolves messy records into a durable golden entity, one per real-world customer, that survives re-runs, carries provenance on every field, and answers "who is this, and where did each value come from?" in a single call.
- A stable identity, not a throwaway cluster id. Every entity gets a stable
entity_id(UUIDv7) that persists across runs as new data arrives. Records are absorbed, entities merge or split, but the id an entity earns is the id downstream systems can rely on. Run-local cluster numbers reshuffle on every run; these don't. - Whole-record provenance. Every field of the golden record traces back to the source record that won it: which source, when it was last seen, and which survivorship strategy picked it. The values it didn't pick stay visible rather than being silently dropped. Provenance is on the whole unified record, not just the match decision.
- Governed by construction. Conflicting values collapse to one best value by an explicit survivorship policy (most-complete · source-priority · most-recent · majority-vote); every identity change lands in an append-only event timeline; and the log is sealed with a hash-chained, tamper-evident audit that a reviewer (or the other language port) can independently verify.
customer_360(entity_id) composes it into one read: golden record, per-field provenance, every linked source record, the event timeline, and the entity's relationship neighborhood:
// customer_360("018f...c2a1") (trimmed)
{
"entity_id": "018f2b7e-...-c2a1", "confidence": 0.97, "record_count": 3,
"sources": ["salesforce", "billing", "support"],
"golden_record": { "name": "Ada Lovelace", "email": "ada@analytical.io", "phone": "+1-555-0100" },
"field_provenance": [
{ "field": "email", "value": "ada@analytical.io",
"winning_source": "billing", "winning_record_id": "billing:8821",
"conflicting_values": [ { "value": "ada@ada.dev", "source": "salesforce" } ] },
{ "field": "phone", "value": "+1-555-0100", "winning_source": "salesforce" }
],
"timeline": [ { "kind": "created", "actor": "pipeline", "recorded_at": "2026-07-30T..." },
{ "kind": "absorbed_record", "reason": "matched billing:8821" } ],
"relationships": [ { "other_entity_id": "018f...9d0e", "kind": "shares_address" } ]
}
What ships today vs. what's emerging. The identity spine is production-grade and in
main: stableentity_ids, per-field provenance, survivorship, merge/split, the append-only log + audit chain, cross-channel stitching, the relationship overlay, and incremental resolution against a persisted index (a new record resolves without a full re-run). Thecustomer_360()serving view above and the source-registry layer that keeps it fresh from live systems are the newer, actively-landing pieces. The source connectors (Snowflake, BigQuery, Salesforce, HubSpot) ship today; the registry that wires them into the spine is emerging. See the Customer 360 design + ADR. We label the seam rather than blur it.
The golden entity lives in the control plane; the matching that builds it runs in the compute engine. That split is the next section.
One product, two engines
The golden entity above is produced by two engines that optimize for genuinely different things, and keeping them distinct is the architecture, not an implementation detail (ADR 0047).
flowchart LR
src([source records])
e360([golden entities · Customer 360])
subgraph compute ["Identity Compute Engine: Arrow-native, Rust-authoritative"]
match[block · score · cluster]
end
subgraph control ["Identity Control Plane: transaction-native state machine"]
spine[stable ids · survivorship · merge/split · provenance · audit]
end
src --> compute -->|resolution batch + evidence| control --> e360
control -.->|persisted index| compute
| Identity Compute Engine | Identity Control Plane | |
|---|---|---|
| Shape | Arrow at bulk boundaries, Rust-authoritative kernels | Transaction-native state machine (SQLite default · Postgres) |
| Job | Block, score, cluster: throughput, vectorized, deterministic per run | Stable ids, survivorship, merge/split, provenance, append-only audit |
| State | Stateless per call; measurement-driven kernelization | Durable, transactional, replayable, auditable |
| Backends | DataFusion · Ray · Sail · Spark are replaceable execution backends, none synonymous with GoldenMatch | Storage backends conform to one externally-observable semantics |
Many surfaces, one answer. The same capabilities reach Python, edge-safe TypeScript (with an opt-in WASM backend running the same Rust kernels), SQL inside PostgreSQL and DuckDB, and MCP / REST / A2A, all governed by specification + conformance, not copy-paste. There is one authoritative owner per capability; pure-Python / standalone-TS paths are classified, conformance-tested fallbacks. Where a boundary can't cross byte-for-byte, we measure and label it rather than claim parity.
Why a platform engineer should care:
- The compute layer isn't framework lock-in. It's Arrow-native and backend-replaceable, so you can push the heavy matching to a query engine that plans, spills, and distributes (verified to 250M rows) without the identity state coming along for the ride.
- The identity layer is a real state machine, not a columnar rebuild-every-time batch. Durable ids, transactional merge/split, provenance and audit are first-class operations you can integrate against.
- Behavior is consistent where it's shared. SQL, Python, and TypeScript track the same answers to a conformance spec, so the surface you build on isn't quietly inventing its own semantics.
Resolution that beats the expert
The identity layer is only as good as the matching underneath it, and the matching starts at zero config. dedupe_df(df) runs with no rules and no training data: it profiles the data, picks a defensible configuration, and returns golden records immediately. The config it chose comes back on result.config: inspectable, diffable, versionable. Never a black box.
- Beats the expert, out of the box. On messy customer records, the opt-in Fellegi-Sunter engine beats hand-tuned Splink head-to-head, with
historical_50kpairwise F1 0.827 vs 0.757, cluster B³ 0.862 vs 0.788, one shared evaluator, reproducible bake-off. Fuzzy, exact, probabilistic (Fellegi-Sunter), and LLM scorers, with EM-trained weights and calibrated scores. - A healing loop, not a one-shot. Zero-config gets you most of the way; then every run checks a free unsupervised signal and, when there's headroom, attaches ranked, self-verified config tweaks to
result.suggestions. Each is kept only if it doesn't worsen a health proxy, so a suggestion never makes results worse.dedupe_df(df, heal=True)applies and re-runs in one call. You close the gap to expert-tuned without being the expert. - Privacy-preserving record linkage. Match across organizations without sharing raw data: Bloom-filter PPRL, 92.4% F1 on FEBRL4, with HMAC-salted encodings.
- Self-verifying. Every step runs preflight + postflight checks and returns an inspectable report instead of failing silently. That is the "advanced, never black-box" contract that makes an automated identity layer safe to build on.
Runs on unstructured input, too: extract records from PDFs and images, then resolve them like any other source (
pip install goldenmatch[documents]).
Runs where your stack is
The engine and the identity layer reach your stack through the surface you already use, with the same capabilities governed by conformance (one product, two engines) rather than re-implemented thinly per surface.
- SQL-native, at parity. The same functions run inside PostgreSQL (pgrx extension) and DuckDB: dedupe · match · score · auto-config + telemetry · identity-graph reads · profiling ·
evaluate· Fellegi-Sunter scoring · GoldenFlow transforms. Resolve without moving data out of the warehouse. - Python and edge-safe TypeScript. The full suite ships on npm alongside PyPI. The TS cores are dependency-free and
node:*-free (browsers, Cloudflare Workers, Vercel Edge, Deno); an opt-in WebAssembly backend (await enableWasm()) swaps in the same pyo3-free Rust kernels the Python wheels and SQL UDFs use, with pure-TS as the byte-identical default. - AI-native by default. Every package ships an MCP server, a REST API, and an A2A agent surface (70+ MCP tools across the suite), all exposing the same JSON telemetry shape across web, TUI, CLI, Postgres, DuckDB, and MCP.
- Spark, with no Python on the executors. The Rust kernels ride into a Spark cluster in one jar (
spark.addArtifact("goldenmatch-spark.jar")) and are called over JNI, so executors need no goldenmatch virtualenv, no packed env, nothing installed. Fellegi-Sunter training runs distributed on that path -- the E-step is a SparkGROUP BYover agreement patterns, so the cluster does the counting and the driver only fits the model. Deployment story, not a throughput one: the JVM scoring path measured ~2.4x slower than the Python-worker path, and the reason to use it is that there is nothing to install. - Pipeline-native. A dbt package (dedupe/match materializations, quality tests, identity-graph reads), a GitHub Action (fail PRs on data-quality regressions), and 13 drop-in Airflow DAGs (Deploy).
- Production paths. Postgres sync, daemon mode, lineage tracking, review queues.
Cross-language parity
Surface parity is not the same as handing any pipeline phase from one language to the other byte-for-byte. Each verdict below is measured by a conformance harness, not assumed:
| Boundary | Verdict |
|---|---|
| Identity graph DB | ✅ byte-safe + cryptographically cross-verifiable (a seal written by one toolkit validates under the other) |
score → cluster and the end-to-end split-run | ✅ byte-safe, reproduces the single-language run |
Cluster JSON · config YAML · Learning Memory · record_fingerprint | ✅ portable |
| String scoring | 🟡 4-decimal tolerance; a pair on a threshold can flip (byte-identical only with the shared WASM scorer) |
| Standardize / dates · embeddings · auto-config controller | 🟠 divergent, not byte-portable |
| Distributed / Ray · document (VLM) ingest | ⛔ Python-only by architecture |
Rule of thumb: hand off at the cluster or identity boundary and it's seamless; don't split across standardize/dates, embeddings, or the controller and expect bit-exact reproduction. Full detail + the runnable harness that keeps these verdicts honest: Cross-language parity & phase-handoff limits.
The suite: the pipeline into the spine
GoldenMatch is the headline, but resolution is only as good as what feeds it. Five sibling tools clean, standardize, and map records before they reach the identity layer. Each stands alone, but they compose into one pipeline, orchestrated declaratively by GoldenPipe:
flowchart LR
raw([raw rows])
golden([golden entities])
subgraph orchestration ["GoldenPipe orchestrates"]
direction LR
infermap[InferMap] --> goldencheck[GoldenCheck] --> goldenflow[GoldenFlow] --> goldenmatch[GoldenMatch]
end
raw --> infermap
goldenmatch --> golden
| Package | Lang | Role in the pipeline | Install |
|---|---|---|---|
| InferMap | Python · TS | Schema mapping: auto-aligns columns across heterogeneous sources | pip install infermap · npm i infermap |
| GoldenCheck | Python · TS | Data-quality scanning: encoding, format validation, anomaly detection | pip install goldencheck · npm i goldencheck |
| GoldenFlow | Python · TS | Transforms & standardizers: phone, date, address, categorical | pip install goldenflow · npm i goldenflow |
| GoldenMatch | Python · TS | Zero-config entity resolution → the identity spine. Headline package. | pip install goldenmatch · npm i goldenmatch |
| GoldenAnalysis | Python · TS | Analysis & reporting: any stage's artifacts → a unified AnalysisReport + cross-run regression detection | pip install goldenanalysis · npm i goldenanalysis |
| GoldenPipe | Python · TS | Orchestrator: declarative YAML wiring the steps | pip install goldenpipe · npm i goldenpipe |
| golden-suite | Python | One-line meta-install: the whole suite + native acceleration | pip install golden-suite |
The deepest docs live in packages/python/goldenmatch/README.md (~1,300 lines: full feature list, CLI, architecture, benchmarks).
Shared components
Not pipeline stages — the pieces the stages agree through, and the single front door an agent points at.
| Package | What it is | Install |
|---|---|---|
| goldencheck-types | Shared canonical field-type registry: one source of truth for what a field type means, across every package and both languages | pip install goldencheck-types · npm i goldencheck-types |
| goldensuite-mcp | One MCP server exposing every suite tool under a single endpoint (stdio or Streamable HTTP) | pip install goldensuite-mcp |
Owned libraries (standalone)
The suite owns its string-matching primitives instead of renting them: byte-identical drop-in replacements, published on their own so they're usable outside the suite too.
| Library | Replaces | What it is | Install |
|---|---|---|---|
| goldenfuzz | rapidfuzz | Fuzzy-string scorers + the full fuzz.* composite family + one-vs-many extract/cdist. Byte-identical (oracle-fuzzed), faster on short strings. | pip install goldenfuzz · cargo add goldenfuzz-core |
| goldenphonetic | jellyfish | Phonetic encoders: soundex / metaphone / nysiis / match-rating. Byte-identical (6,000-input + 2,500-pair fuzz corpus), pure-Rust zero-dep. | pip install goldenphonetic · cargo add goldenphonetic-core |
| goldenmatch-hnsw | FAISS IndexHNSWFlat | Pure-Rust HNSW approximate-nearest-neighbor index (zero C deps). Powers embedding-based blocking across Python, Rust, and TS/WASM. | pip install goldenmatch-hnsw |
Knowledge graphs
Entity resolution is the stage most GraphRAG pipelines do worst: duplicate surface forms of one entity scatter across documents. Two packages put GoldenMatch's resolution there:
| Package | What it does | Status |
|---|---|---|
| goldenmatch-kg | Drop-in GoldenMatch resolution as the ER stage of existing KG frameworks (neo4j-graphrag, LlamaIndex, Graphiti). | in-repo · not published (by design) |
| goldengraph | Build-your-own-KG from text: text → LLM extraction → GoldenMatch resolution → durable bi-temporal store. Rust engine; ER is the differentiator. | in-repo · first PyPI release pending |
Measured, not asserted (ER-KG-Bench): resolution scores F1 0.602 on the labelled set, ahead of Neo4j-KGBuilder (0.456), neo4j-graphrag (0.403), and MS-GraphRAG / LightRAG / Cognee / mem0 (0.066). A resolved graph also does two things passage-window RAG structurally can't: exact aggregation (size-invariant where RAG recall collapses 0.99 → 0.64 across cluster-size buckets) and temporal as-of (1.000 vs 0.002 on past-date queries).
Scale & benchmarks
Every headline number maps back to a single committed runner (scripts/run_benchmarks.py); see docs/reproducing-benchmarks.md for per-number commands, dataset URLs, and expected output with tolerance.
- Accuracy on customer-shaped data. NC Voter 0.9719 F1 (real-data sample), Febrl3 0.9912 F1; the opt-in Fellegi-Sunter path beats hand-tuned Splink head-to-head on every dataset Splink scores ([bake-off](docs/benchmarks/2026-06-09-splink-bakeoff.md
Files in the repo
- .ast-grep
- .claude
- .github
- .ray
- context-network
- docker
- docs
- docs-site
- examples
- packages
- parity
- scripts
- tests
- .context-network.md
- .dockerignore
- .editorconfig
- .gitattributes
- .gitignore
- .mcp.json
- .npmrc
- .pre-commit-config.yaml
- AGENTS.md
- CITATION.cff
- CLAUDE.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- Dockerfile.embprov
- Dockerfile.qis
- justfile
- LICENSE
- llms.txt
- Makefile
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
- pyproject.toml
- pyrightconfig.json
- README.md
- SECURITY.md
- sgconfig.yml
- turbo.json
- uv.lock
Discussion (0)
Ask about usage, or say what you built with itSign in to join the discussion.
No comments yet. Be the first to say what this is good for.
More connectors
High-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds. 158 languages, sub-ms queries, 99% fewer tokens. Single static binary, zero dependencies.

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
Git-native persistent memory for AI coding agents. Implements Google OKF v0.2 with sub-300µs in-memory BM25 search, embedded MCP server, and progressive disclosure. Slashes token bloat by 80% with zero external databases or dependencies. Built in pure Go.
Local-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.
Stop your AI from making things up — it proposes, deterministic tools decide, every claim checked against ground truth with evidence. Grounded facts and context survive resets. Reverse engineering is the proving ground. MCP server + CLI.
