OPEN SOURCE · 26 AUGUST 2026

Article 53 asks what your model was trained on. We open-sourced the tool that answers it.

Shuddhi is Apache-2.0 from today. It takes raw text through provenance gating, deduplication, quality scoring, PII redaction and contamination checks, then seals the result with a build hash anyone can recompute. Including the rule that refuses customer data — which you can now read instead of believing.

TL;DR

What it is. Shuddhi is an Apache-2.0 open-source data factory that turns raw text into an LLM training corpus sealed with a cryptographic receipt anyone can recompute.

Why now. It emits the EU AI Act Article 53(1)(d) training-content summary as a build artefact — enforcement powers have been active since 2 August 2026.

Proven. Reference run: 33,047,370 documents on one two-core VM, no GPU — 97.71% kept, an 84,275-copy duplicate cluster removed, 182,781 PII spans redacted, zero contamination.

Nobody can actually answer the question

Ask any team what their model was trained on. You'll usually get a directory name, a half-remembered filter script, and a sincere assurance that the customer data was excluded. Everyone means it. Almost nobody can prove it. For a long time, that included us.

That was survivable while the question stayed internal. It isn't any more. Article 53(1)(d) of the EU AI Act requires every provider placing a general-purpose model on the Union market to publish a sufficiently detailed summary of training content, on the template the Commission's AI Office issued in July 2025. Enforcement powers became active on 2 August 2026; models already on the market must publish by 2 August 2027. Outside the EU no statute compels it yet — but enterprise procurement and litigation discovery already ask the same question, and "we were careful" isn't an answer to either.

So we built the thing we needed, ran our own corpus through it, and today we're giving it away.

What a receipt actually is

Shuddhi's output isn't just a cleaner corpus. It's a chain of hashes anyone can recompute:

The registry declares where every shard came from — source, licence, acquisition date, data class. From the accepted documents Shuddhi mints a corpus build hash. Applying filters produces a filtered build hash — a content hash of the documents that survived — recorded alongside the corpus hash and a filter-configuration hash that pins every threshold used. Your training run cites the filtered hash in its ledger.

Three properties make it useful rather than decorative. It's order-independent — the hash is over a set, so parallelism can't change it. It's recomputable by anyone holding the same documents, with no key, no server and no configuration of ours — which is exactly why the filter configuration is recorded *beside* the hash rather than folded into it. And the manifest is self-describing: it names the exact configuration that produced the corpus. "Which documents did this model see?" stops being a memory exercise.

We didn't quite believe it ourselves at first, so we reproduced our own corpus hash across four independent full passes of 176 GB. The continuous-integration job still runs the sample pipeline twice on every commit and fails the build if a single hash differs.

What we found in our own data

The first production run covered 33,047,370 documents across 15 languages, on one two-core virtual machine, with no GPU. It kept 97.71% of them. It also turned up things we genuinely didn't expect.

The largest near-duplicate cluster was 84,275 copies of a single template — and it was hiding in the English shard, not the Hindi one. Our earlier sampled measurement had pointed confidently at Hindi — we'd have bet on it, and we'd have lost. Sampling hints; a full pass settles it. That one finding is the whole argument for measuring rather than assuming.

Contamination against our evaluation sets came back zero across every document — not zero in a sample, zero everywhere, which is a different and much stronger statement. And 182,781 spans of personally identifiable information were caught and redacted on the way out — each one something we're glad no model will ever see.

Everyone is counting tokens. Almost nobody is weighing them.

The public numbers are all scale: trillions of tokens, as though the count were the achievement. It's the easiest number to publish and the least informative one, because a token count says nothing about what the tokens *are*. A corpus can be enormous and still be mostly the same page.

We know because it happened to us — and we only caught it because we measured every document rather than sampling. The largest near-duplicate cluster in a 33-million-document corpus was 84,275 copies of one template. Not similar pages — the same thing, eighty-four thousand times, every copy costing GPU hours to memorise something the model already knew after the first.

That's the argument for a data factory in one number. Deduplication, quality scoring and contamination screening aren't hygiene chores that happen before the interesting work; they decide how much of your compute budget teaches the model something new. A smaller corpus you can describe beats a larger one you can't. The frontier labs have known this for years — it's why their papers spend more pages on data than on architecture — and it's doubly true when you're training on a budget rather than a hyperscaler's cluster.

So the honest headline number isn't how many tokens we have. It's what fraction of them survived being measured, what was thrown away, and why — and whether anyone can check the answer. That's what a build hash is for.

Why give away the thing that proves our claims?

Because a claim you can't check is worth very little, and a receipt only we can verify isn't a receipt at all.

The rule that says customer data is evaluation-only and never training is roughly twenty lines of Python. There's no flag, environment variable or plugin hook that turns it off, and a shard tagged as customer data is refused before its file is opened. You can read it in thirty seconds. We'd rather you did than take our word for it.

There's a second reason, and we won't pretend it's altruism. Training-data attestation should be a standard, the way software supply-chain attestation became one. Standards win by adoption, not by ownership. If receipts become normal — including for corpora built with other tools — that's good for everyone shipping models, and we'd like to have been the ones who wrote the reference implementation.

Already using NeMo Curator, DataTrove or Dolma? Keep using them.

Those are good tools and several of them will out-throughput Shuddhi on a web-scale crawl. Out-curating NVIDIA's GPU deduplication is a fight that helps nobody. What none of them emits is a receipt.

So Shuddhi will attest a corpus it did not build: `shuddhi attest --corpus ./out-from-datatrove/ --corpus-id fineweb-slice`. The fingerprint uses the same hash definition a native build uses, so an attested corpus and a Shuddhi-built one are verifiable the same way and comparable to each other.

The honest boundary, stated in the docs and worth repeating: an attestation proves content, not acquisition. It binds a corpus to a hash and reports what's inside it. It can't establish where the data came from — that's what a registry adds.

Run it in one command

`docker run --rm ghcr.io/agentanywhere/shuddhi:1.2.0 demo` runs the entire pipeline over a bundled sample corpus that has defects deliberately planted in it — a duplicate, a near-duplicate, boilerplate junk, a document full of personal data, a contaminated document, and a shard tagged as customer data. You watch each filter catch its target, and you watch the customer shard get turned away at the door. The whole thing takes about ten seconds.

Then point it at your own corpus. There's a quickstart, a user guide, a CLI reference and a troubleshooting page — plus a `doctor` command that tells you whether your Python environment can run the pipeline before anything else has the chance to go wrong. CPU-only throughout: no GPU, no cluster, no account, no telemetry, no network calls.

What's free, and what we sell

Permanently free, under Apache-2.0: the engine, every built-in filter, receipt generation *and verification*, the customer-data refusal, the plugin API, Article 53 summary generation, and attesting corpora built elsewhere. No seat limit. This won't move behind a licence later — several open-core projects relicensed after adoption, and what they lost wasn't revenue but anyone's willingness to build on them again.

Commercial: the hosted receipts registry — a signed, organisation-wide ledger with model-to-corpus-to-licence lookup, retention and legal hold; review workflow for the human sign-off the open engine already demands but gives you no way to manage; cross-build analytics; compliance packs; air-gapped deployment and support.

The line is simple: verification is free, operation at scale is paid. Nothing is ever removed from the open engine to create a paid tier, and commercial filters ship through the same public plugin API anyone else uses — where a paid filter still can't change a corpus without changing that corpus's receipt.

More to follow

Shuddhi is the first of four projects we're opening, and it's deliberately first: it's the one that decides what a model is allowed to learn from. The others follow the same test — we open-source the parts you'd otherwise have to take on faith. The Agent Universal Gateway controls what an agent may call. Model Hub records which model is actually in production. The Annotator labels the data. Each makes a governance claim, and a governance claim you can't read is one you can't check.

AgentAnywhere Core, the commercial platform, isn't open source — and we don't pretend otherwise.

If you have a corpus you have to account for — to a regulator, an auditor, a customer, or your own board — we'd genuinely like to hear from you. We're looking for design partners for the hosted registry, and those conversations shape what gets built.

FAQ

Frequently asked questions.

What is Shuddhi?
Shuddhi is an open-source (Apache-2.0) data factory for LLM training corpora. It takes raw text through provenance gating, language identification, deduplication, quality scoring, PII redaction and contamination checks, then seals the accepted corpus with a build manifest that training runs cite. It also emits the EU AI Act Article 53(1)(d) training-content summary, and can attest corpora produced by other tools such as NeMo Curator, DataTrove or Dolma.
Is Shuddhi really free, and can I use it commercially?
Yes. Shuddhi is licensed under Apache-2.0, which permits commercial use, modification and redistribution. The engine, every built-in filter, receipt generation and verification, the customer-data refusal and the plugin API are permanently open and will not move behind a proprietary licence. The hosted receipts registry, team review workflow, compliance packs and air-gapped deployment are the commercial tiers.
How does Shuddhi help with EU AI Act Article 53?
Article 53(1)(d) requires providers of general-purpose AI models placed on the EU market to publish a sufficiently detailed summary of training content. Shuddhi emits that summary as a build artefact because it already holds the inputs: source, licence, data class, language and acquisition date are required registry fields, so a shard missing any of them is refused rather than defaulted. The output is a draft for your compliance function to review, not legal advice.
Can Shuddhi prove that customer data was excluded from training?
It enforces the exclusion rather than reporting on it. A shard tagged as customer, customer-derived or evaluation-only is refused before its file is opened, and there is no flag, environment variable or configuration field that admits it. Because the engine is open source, you can read that rule yourself rather than accept an assurance, and the refusal is recorded in the build manifest.
Does corpus size matter more than corpus quality for training an LLM?
Token count is the easiest number to publish and the least informative, because it says nothing about what the tokens are. In our own 33-million-document corpus the largest near-duplicate cluster was 84,275 copies of a single template — every copy costing compute to memorise something the model already knew. Deduplication, quality scoring and contamination screening decide how much of a training budget teaches the model something new, which is why a smaller corpus you can describe beats a larger one you cannot.
Do I need a GPU to run Shuddhi?
No. Shuddhi is CPU-only by design. The reference run — 176 GB and just over 33 million documents across 15 languages — was measured and built on a single two-core virtual machine with no GPU and no network access.
Where can I download Shuddhi?
The source is at github.com/agentanywhere/shuddhi under Apache-2.0, and a multi-architecture container image is published at ghcr.io/agentanywhere/shuddhi. Running 'docker run --rm ghcr.io/agentanywhere/shuddhi:1.2.0 demo' executes the full pipeline over a bundled sample corpus in about ten seconds.

Feed your model something you can defend.

The engine is free and open source today — clone it, attest a corpus, generate your Article 53 draft. If you need the hosted registry, review workflow for a team, or air-gapped deployment, talk to us about the design-partner programme.