Project record

mastra-pii

PII redaction for Mastra agents as an adapter, not a detector: one interface over a Presidio deployment — the package owns integration, the deployment owns intelligence — with a deterministic Indian-recognizer layer and fail-closed defaults.

In development State since Aug 9, 2026 TypeScript · Mastra (>=1.57) · Presidio · Node.js
Synthetic document study with sensitive lines obscured
Editorial illustration — a document with sensitive lines obscured, used for the mastra-pii case study, which provides PII redaction with a deterministic fail-closed fallback.

Current state. Live on npm as v0.2.0 (stable) with provenance attestation. One interface, two analyzers: the RemotePresidioAdapter over a deployed Presidio container (spaCy NER + per-request Indian recognizers) and a zero-dependency deterministic engine that doubles as the outage fallback. Extension path: recognizer pass-through (#25) — shipped. P2 hardening complete (#19); no open issues.

Context

The package owns the integration; the deployment owns the intelligence. mastra-pii is an adapter over a Presidio deployment — not a detector — and its story is compatibility and ease of use, not engine accuracy.

Problem

An agent loop touches sensitive text at many surfaces — prompts, tool inputs and outputs, traces, logs, memory — and every one of them needs redaction coverage. The consumer is an agent application whose users write Hinglish and share Indian identifiers (Aadhaar, PAN, UPI, IFSC, bank accounts); Western redaction libraries optimize for English prose and US formats, so off-the-shelf coverage was never the answer. The hard problem that remains is integration: wiring a redaction layer into a Mastra agent normally means custom code at every boundary. The adapter exists so that wiring is zero.

Approach

  1. One interface, two analyzers. RemotePresidioAdapter talks to a deployed Presidio container (spaCy NER by default, plus per-request Indian recognizers); LocalFallbackAdapter is the zero-dependency deterministic engine that takes over on outage. Swap deployments without changing app code.
  2. The deterministic layer ships with the package. INDIAN_DEFAULTS — Indian regex recognizers with client-side Verhoeff (Aadhaar) and Luhn (cards) checksums, a curated entity allowlist, and shape post-filters — sent as per-request ad_hoc_recognizers, and runnable standalone with no deployment at all.
  3. Drop-in Mastra integration. pii.processor implements Mastra’s Processor interface — inputProcessors: [pii.processor] plus outputProcessors is the whole integration, with a third hook (processLLMRequest) covering every model call including tool continuations. Placeholders stay type-tagged ([PAN_1]); custom regexes run in time-bounded worker sandboxes.
  4. Fail-closed by default. Outages degrade to the local engine (or [REDACTION_FAILED] in strict mode); raw PII never leaks.
  5. Layer boundaries explicit. The package accepts only the deterministic layer; ner and model requests are rejected. Adding a model layer or custom recognizers is a deployment-side decision.

Roadmap

The P2 hardening backlog (#19) is complete (2026-08-14) — every ordered item shipped and the package reached stable 0.2.0 on npm. Built-in recognizer expansion (#9–#13) and obfuscation canonicalization (#8) are closed as out of scope — detection extensions flow through recognizer pass-through, not new built-ins.

Resolved (all closed 2026-08-14):

  • #14 — Presidio adapter: retries with jitter + timeout config
  • #25 — Recognizer pass-through: user recognizers (Presidio shape) replace the adapter’s recognizer set; custom patterns (local shape) run in both modes — the documented way to add detection
  • #16 — Observability: per-entity redaction counters
  • #15 — Agent-callable redactPII Mastra tool
  • #17 — Structured-document inspection (redact inside JSON/objects)
  • #18 — Mastra compatibility matrix (1.57 → latest 1.x) — final guard

The repo currently has no open issues.

Evidence

The package is live on npm (provenance-attested), the README documents the full contract, and the repo is public — src/ for the adapter internals, deploy/ for the Presidio recipe. Comparison harnesses live in docs/evaluation/ for internal use; accuracy is the deployed analyzer’s property, not this package’s headline. Portfolio examples are synthetic fixtures only.

Decisions

The published ADR records the starting decision: deterministic local redaction with fail-closed behavior before broader model-backed promises. The pivot to a remote Presidio analyzer was gated on an internal spike before any package work.

Outcome / current state

The package is live on npm (0.2.0, provenance-attested) with 67 passing tests and a clean-consumer verification gate. What it does not do is documented as loudly as what it does:

  • Obfuscated formats still defeat every engine — a stated permanent limit, not a backlog item.
  • Names and addresses are NER-only, deployment-side.
  • International identifiers have no built-in recognizers; pass-through is the extension path.
  • The model layer is explicitly out of scope.

Those limits are scope, not surprises.

Next

The hardening backlog (#19) shipped in full and the package is at stable 0.2.0 — the ordered plan (retries with jitter, recognizer pass-through, observability, the agent-callable tool, structured-document inspection, Mastra compatibility matrix) is done, with no open issues remaining. Future work is deployment-side (NER/model layers) or new scope, tracked as new issues.