Skip to main content
complydoc

Know your documents before they reach an LLM.

An open-source, offline audit for documents before they're indexed.

PyPI Tests Documentation License

Works with
LangChain · LlamaIndex · Unstructured · Docling · LlamaParse · Azure Document Intelligence


complydoc audit flagging a white-text clause in a contract PDF that the loaders passed to the model. The complydoc viewer: a LangChain ingestion pipeline's runs, and one run traced step by step, each loader, splitter, vector store and embedding call on a time axis with its time, cost and the identifiers it passed on, and warnings on a scanned file that loaded no text

A PDF can say one thing to a person and another to your model. White text, tiny type, an IBAN behind a black bar: it's all still in the text layer, and most loaders pass it straight through. complydoc shows you what your loaders actually extracted, page by page, flags the hidden text and the personal and financial identifiers before they're embedded, and can fail a CI check when a document breaks your policy. It also traces every ingestion step with its time and cost, and nothing leaves your machine unless you ask.

Try it in 30 seconds

A one-page contract with a clause in white text:

uv tool install complydoc
curl -LO https://raw.githubusercontent.com/complydoc/complydoc/main/examples/hidden_clause.pdf
complydoc audit hidden_clause.pdf
complydoc ui

Quickstart

uv tool install complydoc        # or: pip install complydoc

Observe an ingestion pipeline as it runs, every loader, splitter, embedding call and vector store a step:

import complydoc as cd

with cd.observe("contracts-ingest"):
    documents = PyMuPDF4LLMLoader("contract.pdf").load()
    chunks = splitter.split_documents(documents)
    vector_store.add_documents(chunks)

Open the run with complydoc ui. Langfuse and Phoenix is how an LLM trace points at the same run.

Compare loaders on your own documents, page by page:

from langchain_community.document_loaders import PyPDFLoader
from langchain_pymupdf4llm import PyMuPDF4LLMLoader

report = cd.compare_loaders(
    {"PyPDFLoader": PyPDFLoader, "PyMuPDF4LLMLoader": PyMuPDF4LLMLoader},
    paths="./contracts",
    page_images=True,
)
cd.write_json(report, ".complydoc/loaders.json", detail="full")
The complydoc viewer: two readers' readings of the same page side by side, with the page itself beside them

Or audit a folder from the command line:

complydoc audit ./contracts

Then open it all in the viewer, served from your machine:

complydoc ui

The playground has all of this ready to run.

Demo

examples/hidden_clause.pdf is one page: two columns, and a sentence in white. examples/hidden_clause.py writes it.

complydoc audit examples/hidden_clause.pdf --compare-extractor pypdf
complydoc check examples/hidden_clause.pdf --policy examples/hidden_clause.yaml
complydoc ui

The audit keeps both readings and flags the white sentence. The check fails on it. complydoc ui opens the report.

Terminal: complydoc audit reports one high hidden passage, then complydoc check fails on the white sentence Viewer security page: the white sentence, marked high, confirmed, white text Viewer document page: complydoc and pypdf side by side, with the white sentence in the text

Six pages of the same kind, and what each loader returns from them, are in What PDF loaders let through.

What it shows

  • Pipeline traces: each LangChain or LlamaIndex loader, splitter and embedding call as a step, with its settings, time, tokens, cost and what it passed on.
  • Loader diffs: every loader's reading of a document side by side, line by line, with the page it came from.
  • Identifiers: personal and financial identifiers from Europe, the Americas, India and Australia, checksum-validated where a checksum exists, and masked until you choose to see them.
  • Hidden content: text a reader does not see and a model does, and passages written as instructions to a model.
  • Chunks: splitters side by side, drawn over the text, with the sentences and tables they cut.
  • Cost: text and vision tokens per page, priced across models and extraction paths.
complydoc architecture: files and loader output feed four analyses (cost, readiness, identifiers, hidden content) that produce a report and masked text, inside a network guard

In CI

complydoc check holds a folder to rules written in YAML and fails when they break. On GitHub, the repository is also an action:

- uses: complydoc/complydoc@v0.7.6
  with:
    path: documents
    policy: policy.yaml

policy can be a file, or a pack that ships with the tool: finance, legal, hr.

See GitHub Action and Policy files.

For a team

One place where everyone opens the same reports, inside your own infrastructure:

complydoc ui ./reports --host 0.0.0.0     # served to your team, read-only
docker run -p 8500:8500 -v "$PWD/reports:/reports:ro" ghcr.io/complydoc/complydoc

Reports can live in a shared folder or a bucket (--out s3://bucket/folder), each run records the repository, branch and commit it came from, and a Compose file puts the viewer behind the sign-in your organisation already has. See Run it for your team and Run it in a container.

Privacy

Outbound connections and DNS lookups are blocked for the whole run, and every report records that they were. Identifiers are masked in every output, the page text included. The only things that send data anywhere are ones you add yourself: a hosted parser or the optional typesafe and assistant extras, which run only with allow_network=True, and a bucket you name as the place to keep reports, which receives the report and never the documents. See Network isolation.

Optional extras

Reading scans and finding names are optional, because they are large. Every report says when they were missing.

Extra Size Adds
ocr ~80 MB Reads scans and images
multilingual-names ~2 GB Finds people and companies in European languages
ner ~50 MB Finds names with spaCy's small English model
s3 ~90 MB Writes reports to a bucket and serves them from one
uv tool install "complydoc[ocr,multilingual-names]"
complydoc doctor              # what is installed, and the command for anything missing

The name models are downloaded once, before a scan, never during one: complydoc doctor prints the command. Detection accuracy publishes how often each finds and misses names.

Resources

License

MIT

Metadata

Release files for complydoc 0.7.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for complydoc 0.7.6
File Size Uploaded
complydoc-0.7.6.tar.gz 6.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for complydoc 0.7.6
File Interpreter ABI Platform
complydoc-0.7.6-py3-none-any.whl Python 3 none any Details

Total release size: 10.6 MB

Release files / complydoc-0.7.6.tar.gz

Download URL complydoc-0.7.6.tar.gz
Size 6.4 MB
Tags Source
SHA-256 checksum
How to use checksums
c35ac75ed581308fdf21edc8e9638e60753a906e8819eb70fb0bea72331388ea
BLAKE2b-256 checksum
How to use checksums
4eef4bed51c94d99b74f6741cdf964d034553f78ccd684bd94553f7c4c234c77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / complydoc-0.7.6-py3-none-any.whl

Download URL complydoc-0.7.6-py3-none-any.whl
Size 4.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
fd37cd5d1d5781f4dd4a1dd21bf266b117bdc5fde1ec39fe73dbfd52ac52bd9c
BLAKE2b-256 checksum
How to use checksums
4735f278fcc02222f06701f870ecf6a0d3cf0d25c474a554ae1f5b11ce5f41f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.6 This release

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.8

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.12

2 release files

0.4.11

2 release files

0.4.10

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page