Skip to main content

Local-first PHI/PII de-identification: rule/NER cascade + local LLM. Your data never leaves your machine.

Project description

localscrub

Local-first PHI/PII de-identification for clinical and free-form text.

Your data never leaves your machine: a fast rule/NER pass catches the obvious identifiers, and a local LLM handles the context-dependent remainder — no cloud APIs, no data crossing your trust boundary.

Status: v0.1 — usable, honest about its limits, pre-1.0 API. New here? Start with the quickstart. Roadmap: ROADMAP.md.

Why

Existing options force a bad trade:

  • Cloud de-id APIs — accurate, but you send the sensitive data out to get it scrubbed.
  • Local rule/NER tools — private, but miss context-dependent PHI in free text ("the patient's sister works at the bakery on Elm Street").

localscrub runs a two-stage cascade entirely on your hardware: cheap detection for the 90%+, a small fine-tuned local model for the ambiguous rest.

Usage

localscrub scrub notes.txt                      # print redacted text
localscrub scrub notes.txt --json               # print the JSON entity report
localscrub scrub notes.txt -o clean.txt --report report.json
localscrub scrub --report-only < notes.txt      # detect without rewriting
localscrub scrub notes.txt --fail-on-detect     # CI gate: exit 3 if anything found
localscrub scrub notes.txt --llm                # + stage 2: local LLM via Ollama
localscrub scrub notes.txt --ner                # + pretrained clinical NER (CPU)

localscrub synth -n 500 --seed 42 -o data/corpora/dev.jsonl   # synthetic eval corpus
localscrub synth -n 500 --seed 42 --diversify -o dev.jsonl    # + local-LLM paraphrase (Ollama)
localscrub mtsamples --fetch -n 100 --seed 42 -o mts.jsonl    # injection benchmark: real prose
localscrub eval data/corpora/dev.jsonl                        # per-entity precision/recall

Current accuracy numbers (including what stage 1 honestly cannot catch yet) live in docs/results.md. On our benchmark of authentic medical-transcription prose, localscrub with the [ner] extra fully redacts 99.9% of planted identifiers on CPU, vs. 75% for Presidio, the standard rules-only baseline — measured by the same harness, reproducible locally: docs/benchmark.md.

Deploying on real clinical text? Read the trust-boundary and residual-risk discussion first: docs/threat-model.md.

Or from Python:

from localscrub import scrub

result = scrub("Reach the patient at test@example.com.")
result.redacted      # 'Reach the patient at [EMAIL_1].'
result.entities      # (Entity(type=EMAIL, start=21, end=37, confidence=0.95, ...),)
result.escalations   # spans stage 1 couldn't settle — stage 2's work queue

Stage 1 (rules) currently detects: emails, phone/fax numbers, SSNs, credit cards (Luhn-validated), IP addresses, URLs, dates and ages over 89, and labeled MRN / health-plan / account identifiers. Uncertain or ambiguous spans are redacted fail-closed and flagged for stage-2 adjudication. The [ner] extra (pip install 'localscrub[ner]', then --ner) adds a pretrained clinical NER model for person/place names on CPU. Stage 2 (--llm, or scrub(text, stage2=LlmExtractor())) runs a local Ollama model for narrative identifiers and escalation adjudication; see ADR 0002 for its contract.

Entity coverage

All 18 HIPAA Safe Harbor identifier categories (45 CFR 164.514(b)(2)), plus generic PII that matters in practice: credit cards, passports, national IDs, and leaked credentials/secrets. See src/localscrub/entities.py.

License

Apache-2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

localscrub-0.1.0.tar.gz (235.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

localscrub-0.1.0-py3-none-any.whl (53.2 kB view details)

Uploaded Python 3

File details

Details for the file localscrub-0.1.0.tar.gz.

File metadata

  • Download URL: localscrub-0.1.0.tar.gz
  • Upload date:
  • Size: 235.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for localscrub-0.1.0.tar.gz
Algorithm Hash digest
SHA256 312c2f8ac24217ebc1152066f09fa4b3920a52765469908781ab752640bcab5d
MD5 7b401edf6011ea02a747f6b573a79b40
BLAKE2b-256 3712652c4ed2624509c164458122330a40d8b6cec4849ba499b84d0790f43d68

See more details on using hashes here.

File details

Details for the file localscrub-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: localscrub-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 53.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for localscrub-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d630a927e63dae1a410bbd024c7ffb3fcd30a1345d5aaa86008f63fc4f6c90fd
MD5 7f7f624f71ac644c96438722c8a2ba4e
BLAKE2b-256 8577308eba0d2aefab7d4cef3751535f211b2c7ff2ea2a5e962117b0d50c0c74

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page