Content
# privacy-filter
Drop-in PII detection and redaction. One small Python package, three ways to plug in:
1. **Library** — `pip install` and call it in-process. Only dependency: pydantic.
2. **REST API** — `privacy-filter` starts a local FastAPI server. Any language can call it.
3. **MCP server** — `privacy-filter-mcp` exposes it as Model Context Protocol tools for Claude and other LLM agents.
4. **Docker** — optional. A Dockerfile is included, but nothing requires it.
Detection layers: 11 deterministic regex rules (emails, UK phones, postcodes, NI numbers,
bank details, secrets, …), heuristic name/address/date patterns, and — optionally — the
`openai/privacy-filter` token-classification model for ML-grade person/address detection.
Results always say which engine ran (`rules-only` or `model+rules`).
> New here? Read the plain-English **[Overview](docs/overview.md)**, or jump to the
> **[Technical Reference](docs/technical-reference.md)** for the deep dive.
⭐ If you find this useful, give the repo a star — it helps other people find it.
## See it in action

That's the [document redactor example app](examples/document-redactor/) — a
drag-and-drop web page that runs entirely on your machine:
```powershell
pip install .
python examples\document-redactor\app.py
```
## Library
```powershell
pip install . # from the repo root (or the path where you cloned it)
```
```python
from privacy_filter import redact
result = redact("Email jane.smith@example.org or call 07700 900123.")
print(result.text) # Email [EMAIL REDACTED] or call [PHONE REDACTED].
print(result.findings) # spans with type, offsets, confidence
```
See `examples/quickstart.py` for policies and the reusable `Redactor` engine.
## REST API (no Docker required)
```powershell
pip install ".[server]" # from the repo root
privacy-filter
# -> serving on http://127.0.0.1:8081 (POST /v1/redact, POST /v1/detect, GET /health)
```
See `examples/rest-examples.md` and `.env.example` for configuration.
## Enable the ML model (optional)
```powershell
pip install ".[model]" # from the repo root
# download weights once (or copy them in for air-gapped machines):
python -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='openai/privacy-filter', local_dir='models/privacy-filter', ignore_patterns=['onnx/*','original/*'])"
$env:PRIVACY_FILTER_MODEL_PATH = "C:\path\to\models\privacy-filter"
privacy-filter # /health now reports "model+rules"
```
Library equivalent: `Redactor(model_path=r"C:\path\to\models\privacy-filter")`.
By default the package **never downloads anything**: `local_files_only=true` unless you
opt out, the server binds to `127.0.0.1`, input text is never logged, and the server
rejects request bodies over 64 KiB (`PRIVACY_FILTER_MAX_TEXT_BYTES`, default `65536`)
as a denial-of-service guard — raise it if you need to process larger documents.
## Claude / MCP integration
Expose the module to Claude (and any MCP client) as local tools — it imports the
library in-process, so there's no network hop and nothing extra to run:
```powershell
pip install ".[mcp]" # from the repo root
privacy-filter-mcp # stdio MCP server
```
Wire it into Claude Code / Claude Desktop by adding this to your `.mcp.json`
(see `examples/claude-mcp-config.json`):
```json
{
"mcpServers": {
"privacy-filter": { "command": "privacy-filter-mcp" }
}
}
```
Tools exposed: `redact_text(text, policy?, threshold?)`, `detect_pii(text, policy?, threshold?)`,
and `list_policies()`. The same `PRIVACY_FILTER_*` env vars apply (model path,
default policy, size cap).
A ready-made Claude skill lives in [`skills/pii-redaction/`](skills/pii-redaction/SKILL.md) —
it teaches Claude when and how to redact PII with these tools. Copy or symlink it
into your `~/.claude/skills/` (or a plugin's `skills/`) to activate it.
## Policies
A policy says which categories get redacted (a category is active iff it has a label),
what replaces them, and the review threshold. Presets: `default`,
`witness_statement_external_disclosure`, `training_data_sanitisation`,
`transcript_standard`, `external_sharing`.
```python
from privacy_filter import Policy, Redactor
emails_only = Policy(name="emails_only", labels={"private_email": "<email removed>"})
Redactor(policy=emails_only).redact("Write to a@b.co")
```
Load a policy from a JSON file in library code:
```python
from pathlib import Path
policy = Policy.model_validate_json(Path("my_policy.json").read_text())
```
Servers can register extra policies at startup: `PRIVACY_FILTER_POLICY_FILE=policies.json`
(a JSON list of Policy objects).
Low-confidence findings from the rule and heuristic detectors are **redacted and
flagged** (`review_required=true`, `reason="low_confidence"`), never silently
dropped. The optional ML detector is the one exception: it filters spans scoring
below the threshold at the source (they are not returned or flagged), so lower
the threshold if you want borderline ML detections surfaced for review.
## Docker (optional)
```powershell
docker build -t privacy-filter .
docker run --rm -p 8081:8081 privacy-filter
# with the ML runtime baked in and local weights mounted:
docker build --build-arg INSTALL_MODEL_RUNTIME=true -t privacy-filter:model .
docker run --rm -p 8081:8081 -v C:\path\to\models\privacy-filter:/models/privacy-filter `
-e PRIVACY_FILTER_MODEL_PATH=/models/privacy-filter privacy-filter:model
```
## Development
```powershell
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev,server,mcp]"
.\.venv\Scripts\python.exe -m pytest
```
## Documentation
- **[docs/overview.md](docs/overview.md)** — plain-English guide for non-technical readers (what it does, how to use it, how good it is, privacy).
- **[docs/technical-reference.md](docs/technical-reference.md)** — full technical reference (architecture, pipeline, data models, Python/REST/MCP APIs, config, security, extending).
- **[docs/README.md](docs/README.md)** — docs index.