Mask the person,
keep the meaning —
on-device
Real-time, on-device redaction. Strip PII into cryptographically isolated tokens before text reaches an LLM — and a separate vault restores the originals after the model responds. Rust core, with Python and Node bindings.
What the model sees. What the vault keeps.
Each sensitive span becomes an opaque [RTKN_…] token. The LLM only ever sees the tokens; the token→original mapping lives in a separate vault, never returned inline with the text.
With reversible mode, unredact() swaps the tokens back after the model responds — using the vault you kept, not anything the model returned.
Send the report to [RTKN_3f8a2c1d] by Friday.
restored = redactor.unredact(llm_out, result.vault) → originals restored (reversible=True)Five commitments the mask has to keep.
Redaction is only trustworthy if the guarantees underneath it are. These hold whether you take the one-way default or keep a vault to restore — and they're why redact is a separate library, not a checkbox.
On-device by default
The default path makes zero network calls. Detection and masking run in-process, on your machine — there's nothing to send and no service to trust. Cloud-assisted recognizers are an explicit opt-in that warns on first use.
The vault is never inline
Redacted text and its token→original mapping are never returned together. The vault is always a separate object — a deliberate architectural commitment, so the text and the key to it don't travel as one.
Reversible when you need it
One-way by default: tokens can't be reversed. Opt into Redactor(reversible=True) and unredact() restores the originals from the vault after the LLM has responded — the model only ever saw tokens.
Fresh salt every call
Each redact() uses a fresh 128-bit random salt, so tokens from different calls never collide — even for identical input values. The same person can't be re-correlated across records by their token.
Category-aware profiles
Profiles tied to Shield workflows (shield-legal, shield-finance) add domain entities like CASE_NUMBER and BATES_NUMBER on top of the default PII set — so redaction matches the sensitivity model that classified the text.
Run ogentic-shield first to decide what needs redacting; redact then masks it. Detect and mask are separate jobs, on purpose.
A token, and the vault it points to.
A redacted span becomes an opaque token; the mapping back to its original value lives in a separate vault object. The text and the key to it never travel together — that's the whole design.
Alice Johnson, SSN 123-45-6789, called about her claim.
[RTKN_a1b2c3d4], SSN [RTKN_e5f6a7b8], called about her claim.
- Token
- [RTKN_<hex>] — opaque, non-guessable
- Salt
- fresh 128-bit random, per call
- Vault
- separate object; token → original
- Default
- one-way (no mapping kept)
- Reversible
- Redactor(reversible=True)
- Restore
- unredact(text, vault)
Redacted text and its mapping must not be collocated after the call returns. The design and its boundaries are written up in the threat model ↗.
Wherever text has to be shared but identity can't.
The same job everywhere: let an LLM work on the shape of the content without ever handling the people inside it — then, when you need to, put the names back.
Discovery without the exposure
Strip client names, SSNs, and case numbers from documents before an LLM summarizes them — then restore from the vault when the summary comes back. The model sees structure, never identity.
PHI never reaches the model
Patient identifiers are tokenized on-device before any transcript or note is summarized. HIPAA-shaped by construction: what leaves the box is de-identified, reversibly, only if you keep the vault.
Sotto Meeting Mode, step 2
In a live meeting, Shield classifies the transcript and Redact strips PII before it's sent to any LLM for summarization — and every redaction event is recorded by Audit.
De-identified logs and tickets
Tokenize PII in logs and support tickets before they leave the machine. Per-call salts mean the same person can't be re-correlated across records by their token.
Detect, tokenize, isolate — then restore.
Five steps from raw text to a clean surface and back again. The one that makes it safe is the third: the mapping is split off into a vault the moment the tokens are minted.
detectLocate the sensitive spans
Entity detection runs on-device — or takes Shield's spans — to find names, emails, SSNs, and any profile-specific entities in the text.
redact()Mint isolated tokens
Each span becomes an opaque [RTKN_…] minted with a fresh 128-bit salt, so tokens never collide across calls.
vaultSplit off the vault
The token→original mapping goes into a separate vault object — never returned inline with the redacted text.
→ LLMSend clean text onward
The redacted surface goes to the LLM or any downstream service. It carries the shape of the content, never the identities inside it.
unredact()Round-trip back
When the response returns, unredact() swaps tokens for originals using the vault — reversible mode only. The default keeps nothing.
detect → redact() → vault → → LLM → unredact()// The vault is never returned inline — redacted text and its mapping must not be collocated after the call returns.
One default, plus profiles that match Shield.
The default profile covers common PII out of the box. Named profiles tie to Shield's workflows and add domain entities on top — so what you redact matches what classified the text. Cloud-assisted recognizers are an opt-in extra.
Default PII
The common set — names, emails, phone numbers, SSNs, and more. Works out of the box, no configuration.
- PERSON · EMAIL_ADDRESS
- US_SSN · PHONE_NUMBER
- no setup
Legal
Adds legal-domain entities on top of the default set — case numbers, Bates numbers — matched to the shield-legal workflow.
- CASE_NUMBER · BATES_NUMBER
- privilege-aware
- matches shield-legal
Finance
Finance-domain entities aligned to the shield-finance workflow — account and instrument identifiers on top of the default PII set.
- account / instrument IDs
- MNPI-adjacent
- matches shield-finance
Both can mask text. They solve different problems.
ogentic-shield ships a lightweight, inline redaction for single-shot contexts the caller owns. ogentic-redact is for when the mapping has to live somewhere the text doesn't — with reversibility and stronger de-correlation.
- Mapping location
- Inline in the response
- Reversibility
- One-way only
- Salt / de-correlation
- None
- Category defaults
- Fixed entity set
- On-device guarantee
- Depends on config
- Mapping location
- Separate vault (opaque id)
- Reversibility
- Explicit opt-in
- Salt / de-correlation
- Per-call 128-bit salt
- Category defaults
- Profile system
- On-device guarantee
- Default: zero network
Reach for Shield's redaction when you want a quick inline mask in a context you own. Reach for Redact when you need vault isolation, a reversible round-trip, or per-call de-correlation — the mapping never sitting next to the text. Run ogentic-shield ↗ first to decide what needs redacting.
Two lines to a clean surface.
A Rust core with Python and Node bindings — same engine, same tokens, everywhere. One-way by default; opt into the vault when you need to put the originals back.
from ogentic_redact import Redactor
redactor = Redactor()
result = redactor.redact("Send the report to alice@example.com by Friday.")
print(result.text)
# Send the report to [RTKN_3f8a2c1d9e4b7a6f] by Friday.
# Tokens are non-reversible by default. A fresh 128-bit salt per call
# means tokens never collide across calls, even for identical input.from ogentic_redact import Redactor
redactor = Redactor(reversible=True)
result = redactor.redact("Alice Johnson, SSN 123-45-6789, called about her claim.")
# result.text -> [RTKN_a1b2c3d4], SSN [RTKN_e5f6a7b8], called about her claim.
# send result.text to your LLM — it never sees PII
llm_out = "[RTKN_a1b2c3d4] has a pending claim for [RTKN_e5f6a7b8]."
restored = redactor.unredact(llm_out, result.vault)
# Alice Johnson has a pending claim for 123-45-6789.from ogentic_redact.profile import Profile, KNOWN_PROFILES
print(KNOWN_PROFILES)
# frozenset({'shield-legal', 'shield-finance'})
# legal adds CASE_NUMBER, BATES_NUMBER on top of the default PII set
profile = Profile.from_shield_profile("shield-legal")
print(profile.entity_types)pip install ogentic-redact # Python npm install @ogenticai/redact-darwin-arm64 # Node (macOS arm64) cargo add ogentic-redact # Rust
Shield finds it. Redact hides it.
Composable Apache-2.0 primitives for regulated AI. Shield reads sensitivity; Redact masks it on-device; Router decides where the clean text goes; Audit records what happened. Four are live today.
classify → redact → route → prove · Redact is the masking step right after ogentic-shield ↗ and before ogentic-router ↗ — part of the OgenticAI ↗ OSS suite.
Install it. Redact in two lines.
Python, Node, or Rust — one engine, the same tokens everywhere. On-device by default; add the vault when you need to restore. No account, no telemetry.
npm install @ogenticai/redact-darwin-arm64 · cargo add ogentic-redact