Skip to main content

Reversible PII pseudonymization for the full AI agentic loop.

Project description

Legend

Python License PyPI Downloads Status

PII pseudonymization for the full agentic loop.


Agent pipelines expose PII at every step: in user prompts, tool call arguments, tool results, and final responses. Legend intercepts at all four points, replacing PII with realistic pseudonyms before it reaches external APIs or leaves your infrastructure, and restoring the original values exactly in the final response.


Design

The pseudonymization strategy is grounded in recent research showing that realistic substitutes preserve utility significantly better than suppression or redaction across multi-turn interactions. Legend extends the single-boundary pseudonymization approach of LOPSIDED (Serenari & Lee, 2025) to the full four-boundary agentic loop, addressing the leakage surface that existing tools leave uncovered.


Getting Started

Requirements

  • Python 3.13+
  • No external API keys. Legend runs entirely on your infrastructure.

Install

pip install legend
legend download-models

The download-models command fetches the spaCy model weights to ~/.legend/models/. Run this once before first use. If you skip it, Legend downloads the model automatically on first run.

For custom model locations (containerized or edge deployments), set LEGEND_MODEL_PATH before running:

LEGEND_MODEL_PATH=/mnt/storage/legend 
legend download-models

Use

import asyncio
from legend import DetectionPipeline, ReplacementEngine, PseudonymContext

pipeline = DetectionPipeline(entities=["PERSON", "EMAIL_ADDRESS", "US_SSN"])
engine = ReplacementEngine()

async def run():
    async with PseudonymContext(pipeline=pipeline, engine=engine) as ctx:

        # Boundary A: user prompt entering the agent
        prompt = await ctx.sanitize_prompt(
            "Process a refund for John Smith (john.smith@acme.com), SSN 123-45-6789."
        )
        # "Process a refund for Michael Torres (fake3847@example.com), SSN 987-65-4320."

        # Boundary B: tool call arguments leaving toward an external API
        args = await ctx.sanitize_tool_args({"email": "john.smith@acme.com", "amount": 150})
        # {"email": "fake3847@example.com", "amount": 150}

        # Boundary C: tool results entering the agent context
        result = await ctx.sanitize_tool_result(tool_response)

        # Boundary D: real values restored in the final response
        response = await ctx.revert(agent_response)

asyncio.run(run())

DetectionPipeline and ReplacementEngine are initialized once and reused across sessions. A fresh session-scoped entity map is created for each PseudonymContext block and destroyed on exit.


The Four Boundaries

Agent pipelines expose PII at four distinct points. Legend intercepts all of them.

A — User prompt in. PII in the user's message is replaced before it enters the agent's context window.

B — Tool call arguments out. PII that the agent constructs into tool call arguments is replaced before it reaches an external API, database, or service.

C — Tool result in. PII returned by a tool (fetched from a database, retrieved from an external system) is replaced before it enters the agent's context.

D — Response out. Pseudonyms are reverted to their original values in the final response before the user sees it.

Most tools protect only the prompt. Boundary B and Boundary C are where agent-specific leakage happens and where Legend is different.


Properties

Reversible. Real values are restored exactly at Boundary D. The agent's response reads naturally, with original names, addresses, and identifiers intact.

Realistic substitutes. A name becomes a plausible name. An IBAN becomes a valid-format IBAN with the correct country code and check digit. Agents reason correctly over pseudonymized data because the substitutes are semantically coherent.

Session-scoped. The entity map lives only for the duration of a PseudonymContext block. No state persists between sessions. No database required.

On-premise. Detection runs via YARA rules and a local spaCy model. Nothing leaves your infrastructure during processing.

Framework-agnostic. Works with LangGraph, LangChain, CrewAI, or any agent framework. PseudonymContext wraps your existing agent calls with no framework-specific integration required.


Custom Rules

Legend ships with detection rules covering the full Presidio entity list. For domain-specific PII formats (internal account IDs, regional document numbers, custom identifiers), generate additional YARA rules with yaramint and pass the rules directory to DetectionPipeline.


Roadmap

  • Framework adapters. One-line integration for LangChain, LangGraph, and CrewAI via wrap_langchain_tools() and equivalents. No tool-level boilerplate.
  • Transparent proxy. An OpenAI-compatible HTTP proxy that intercepts MCP tool calls at the protocol level. Works with any agent framework, zero code changes required.
  • OpenTelemetry integration. Optional legend[otel] extra that routes pseudonymized observability events into any OTel-compatible backend. Each session maps to a trace, each boundary to a child span.

References

Xiao, Yunze, Wenkai Li, Xiaoyuan Wu, Ningshan Ma, Yueqi Song, and Weihao Xuan. Say Something Else: Rethinking Contextual Privacy as Information Sufficiency. arXiv:2604.06409. Preprint, arXiv, April 7, 2026. https://doi.org/10.48550/arXiv.2604.06409.

Serenari, Jayden, and Stephen Lee. Semantically-Aware LLM Agent to Enhance Privacy in Conversational AI Services. arXiv:2510.27016. Preprint, arXiv, October 30, 2025. https://doi.org/10.48550/arXiv.2510.27016.

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

legend_pii-0.1.0.tar.gz (114.9 kB view details)

Uploaded Source

Built Distribution

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

legend_pii-0.1.0-py3-none-any.whl (41.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: legend_pii-0.1.0.tar.gz
  • Upload date:
  • Size: 114.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for legend_pii-0.1.0.tar.gz
Algorithm Hash digest
SHA256 74b2fae9c37b931666481fa7aaa180161fef5143ffe378cb9450d51f44053021
MD5 8954a7965c34c8ceb4c5d3eb44c250e1
BLAKE2b-256 1b509f9b094186855c027524676ed445d84fe17692b83359fbabb8b759b00deb

See more details on using hashes here.

Provenance

The following attestation bundles were made for legend_pii-0.1.0.tar.gz:

Publisher: release.yml on deconvolute-labs/legend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: legend_pii-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 41.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for legend_pii-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 06ae096dd138b96c18b9fa61f9ff5f8831e082a3e1aba2ac4ecb0f9996992275
MD5 667442d8797c64e95b4827df4dd49c21
BLAKE2b-256 90f48578779972a1cad5c95dee8fd53143448986dd6aafd101db4ce260fd9841

See more details on using hashes here.

Provenance

The following attestation bundles were made for legend_pii-0.1.0-py3-none-any.whl:

Publisher: release.yml on deconvolute-labs/legend

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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