{"owner":"microsoft","repo":"presidio","hasSkills":true,"totalSkillsCount":6,"totalTokensCount":4078,"categories":["root-instruction","copilot-instructions","claude-rule","mcp-config","marketplace","plugin-manifest"],"hasMcp":true,"mcpConfig":{"mcpServers":{"presidio":{"command":"npx","args":["-y","@modelcontextprotocol/server-presidio"]}}},"found":["AGENTS.md",".github/copilot-instructions.md","CLAUDE.md",".cursor/mcp.json",".claude-plugin/marketplace.json",".claude-plugin/plugin.json"],"skills":{"AGENTS.md":"# Presidio — Agent Guidelines\n\nPresidio is a Python SDK for detecting (presidio-analyzer) and anonymizing\n(presidio-anonymizer) PII in text and images, plus CLI, structured-data, and\nimage-redaction components. It is a widely used **library**: users depend on\ncurrent detection behavior, and configuration files written years ago must keep\nworking. Correctness and backward compatibility outrank cleverness.\n\nThe review-side versions of these rules — which the Copilot PR review agent\nalso enforces — live in `.github/copilot-instructions.md` and\n`.github/instructions/*.instructions.md`. Follow them at authoring time so the\nreview finds nothing.\n\n## Working in this repo\n\n```bash\ncd presidio-analyzer            # or presidio-anonymizer, presidio-cli, ...\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg   # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n```\n\n- Python `>=3.10,<3.15`; code must run on every version in range.\n- Dependencies are managed with **uv**, not pip/Poetry. If you touch a\n  package's `pyproject.toml` dependencies, run `uv lock` in that package and\n  commit the updated `uv.lock` in the same change — CI fails on drift.\n- Do not edit `CHANGELOG.md`; release entries are generated from merged PRs.\n- Never log PII values (`entity.text`) — only entity types and positions.\n- Modules that process records are stateless; do not add state.\n- Terminology: \"threshold\", not \"cutoff\"; ISO 639-1 language codes everywhere.\n\n## Adding a PII recognizer\n\nThe full rulebook — score bands, context-word rules, validation-hook\nsemantics, the configuration-path test template, and the test-quality bar —\nis `.github/instructions/recognizers.instructions.md`. **Read it before\nstarting**; those rules apply at authoring time, not just in review. The\nworkflow, in order:\n\n1. **Place and name it** under `predefined_recognizers/`: full lowercase\n   country name for new country directories (`south_africa`, not `za`;\n   don't imitate the pre-existing short forms `us`/`uk`/`thai`), or\n   `generic/`, `nlp_engine_recognizers/`, `ner/`, `third_party/` as\n   appropriate.\n2. **Use ISO 639-1 language codes** (`ko` for Korean, never `kr`) — a\n   mismatch loads nothing, silently.\n3. **Make the constructor loader-compatible**: accept the YAML loader's\n   kwargs (`name`, `supported_entity`, `context`, ...) and forward them to\n   the base class, or the recognizer crashes the whole registry the moment a\n   user enables it.\n4. **Design the pattern for accuracy first** — this is the top review\n   priority: as specific as the format allows, score calibrated to the\n   pattern alone, unambiguous context words, the correct checksum if one\n   exists (and none invented if it doesn't), and the pattern's source\n   documented in the docstring, preferably an official specification.\n5. **Register it everywhere**: exports in `predefined_recognizers/__init__.py`\n   *and* the country/category `__init__.py`; an entry in\n   `conf/default_recognizers.yaml` (country-specific ships `enabled: false`);\n   a row in `docs/supported_entities.md`.\n6. **Write the configuration-path test** — the most-missed step and the one\n   that matters most: enable the recognizer in a YAML config, load it through\n   `RecognizerRegistryProvider`, and assert detection (template in the\n   instructions file). Non-English recognizers must set the top-level\n   `supported_languages` in the test config — it defaults to `[\"en\"]` and\n   silently filters everything else.\n\nWhen **modifying** an existing recognizer: changed patterns, scores, or context\nchange detection results for existing users — state that in the PR description,\nand never change an existing recognizer as a side effect of adding a new one.\n\n## Changing the YAML configuration layer\n\nThe rulebook for the pydantic models in `presidio_analyzer/input_validation/`\nis `.github/instructions/yaml-config.instructions.md` — **read it before\ntouching the layer**. The short version:\n\n- Constructor parameters and schema fields must never drift apart: a\n  YAML-settable kwarg without a matching pydantic field is silently dropped\n  today. Model-specific kwargs need a dedicated config model registered in\n  `CONFIG_MODEL_MAP`.\n- Choose `extra` deliberately (`forbid` fails fast, `allow` passes through);\n  pass-through models dump with `exclude_none=True` so YAML omissions keep\n  constructor defaults.\n- Validate at parse time with actionable messages, and never break existing\n  YAML — legacy singular fields, bare-string entries, and inferred `type` all\n  stay supported.\n- Test through `RecognizerRegistryProvider`, not just the pydantic model:\n  prove new fields reach the constructed object and assert error *messages*\n  for invalid YAML.\n\n## General engineering rules\n\n- **Declare behavior changes.** Any edit outside a brand-new file needs the PR\n  description to say what existing behavior changes. Defaults on shared base\n  classes, properties on abstract interfaces, and anything altering returned\n  entities or scores all count, even with no signature change.\n- **Explainability**: anything that changes how a score is derived must be\n  reflected in `AnalysisExplanation`.\n- **Component boundaries**: data flows Analyzer → Anonymizer → Output; import\n  public interfaces, never another component's internals; shared models\n  (`RecognizerResult`, `OperatorConfig`) are contracts — update all consumers\n  in the same changeset.\n- **Anonymizer operators**: non-reversible by default — no deterministic\n  hashing (rainbow tables), unpredictable replacement values, no preserved PII\n  characteristics. Deterministic or format-preserving output is sometimes a\n  hard requirement (e.g. referential integrity across a dataset); support it as\n  an explicit, documented opt-in, never as the default behavior.\n- **Security**: never log PII values; validate untrusted inputs before use\n  (user-supplied regexes before compilation, file paths, API payloads); no\n  hardcoded secrets; no unsafe deserialization of untrusted models or pickles.\n- **Performance**: no catastrophic regex backtracking (test long adversarial\n  inputs); cache compiled regexes; batch NLP with `nlp.pipe`.\n- **Docs move with code**: `docs/supported_entities.md` for entities,\n  `docs/api-docs/api-docs.yml` for API changes, reST docstrings on public\n  APIs, samples for complex features.\n",".github/copilot-instructions.md":"# Presidio Development & Review Instructions\n\nPresidio is a Python-based data protection and de-identification SDK with\nmultiple components for detecting and anonymizing PII (Personally Identifiable\nInformation) in text and images.\n\nDomain-specific rules live in path-scoped instruction files and apply on top of\nthis file when a change touches the matching paths:\n\n- `.github/instructions/recognizers.instructions.md` — adding or modifying PII\n  recognizers.\n- `.github/instructions/yaml-config.instructions.md` — the pydantic layer that\n  translates YAML configuration into Presidio instances.\n\n## Core Philosophy\n\n**Data privacy is paramount.** This is a PII detection and anonymization system\nused in sensitive contexts; security and correctness are non-negotiable.\n\n- **Accuracy first**: false negatives (missed PII) and false positives\n  (incorrect detections) both damage trust.\n- **Security by default**: never log PII values, use non-reversible\n  anonymization, validate all inputs.\n- **Presidio is a library**: changes to shared code alter results for users who\n  wrote no new code. Backward compatibility is the prime directive.\n- **Stateless design**: modules that process records are stateless for\n  scalability — avoid adding state.\n- **Cross-component awareness**: Presidio is a multi-component system; changes\n  ripple across boundaries.\n- **Documentation integrity**: code and docs must stay synchronized — outdated\n  docs are dangerous.\n\n## Backward Compatibility\n\nBefore changing anything outside a brand-new file, the PR description must\nstate what existing behavior changes. These count as behavior changes even\nwithout a signature change:\n\n- Default values on shared base classes (`None` to `[]` changes truthiness for\n  every subclass).\n- Properties on abstract interfaces — custom implementations inherit the new\n  default and may break.\n- Anything altering which entities are returned, or their scores, for text that\n  previously worked.\n\nPrefer additive changes: new parameters get defaults preserving current\nbehavior; public APIs are never broken without a deprecation path.\n\n**Surface new scoring inputs in explainability.** Anything that changes how a\nscore is derived (context, negative context, thresholds) must be reflected in\n`AnalysisExplanation`, or users cannot tell why a result scored as it did.\n\n**Prefer warnings over exceptions when the caller cannot fix the condition.**\nRaising on a configuration a user did not write turns a degraded result into a\nhard failure. Where a lookup falls back to a default, add a debug log so the\nfallback is discoverable.\n\n**Prefer a property on the base class over a maintained list of class names.**\nLists drift as classes are added, and users installing from PyPI cannot extend\nthem.\n\n## Cross-Component Changes\n\nData flows one way: Analyzer → Anonymizer → Output. Downstream components\n(CLI, structured, image-redactor) consume analyzer/anonymizer, never the\nreverse.\n\n- Shared data models (`RecognizerResult`, `OperatorConfig`) are contracts —\n  changes require coordinated updates across all consumers, in the same\n  changeset.\n- Reuse by importing from shared modules, not by copying code across\n  components. If multiple components need a feature, extract it to a common\n  location.\n- Respect boundaries: a component imports another's public interface, never its\n  internals (e.g. the anonymizer must not import\n  `presidio_analyzer.predefined_recognizers`).\n- Registry and provider patterns exist to decouple components — bypassing them\n  creates hidden dependencies.\n- Test the complete integration path (unit, integration, and e2e), not just\n  isolated components.\n\n## Security & Privacy\n\nAlways flag:\n\n- **PII leakage in logs, errors, or debug output** — log entity types and\n  positions, never `entity.text`.\n- **Reversible or weak anonymization** — deterministic hashing is reversible\n  via rainbow tables; use random/unpredictable replacement values that don't\n  preserve PII characteristics.\n- Regex injection: user-provided patterns must be validated before compilation.\n- Hardcoded secrets or credentials; unsafe deserialization (pickle, untrusted\n  models); command injection; path traversal; missing input validation on API\n  endpoints (including unbounded input sizes).\n\n## Performance\n\n- Avoid catastrophic regex backtracking (`(a+)+b` is O(2^n) on `aaaa...b`);\n  test patterns against long adversarial strings.\n- Cache compiled regexes; don't recompile per call.\n- Batch NLP processing (`nlp.pipe`) instead of per-text calls; load models\n  once and reuse.\n- Flag O(n²) where O(n) exists, blocking I/O on API paths, and loading entire\n  datasets into memory.\n\n## Testing Standards\n\n- Test names describe behavior:\n  `test_when_invalid_checksum_then_no_match`, not `test_case2`.\n- Assert exact expected values, not ranges — a range assertion passes even when\n  the logic producing the value breaks.\n- Cover true positives, true negatives, edge cases, and values embedded in\n  surrounding text; validate exact boundaries, not just types.\n- Fix random seeds for non-deterministic NLP/ML tests.\n- Test behavior, not implementation details.\n\n## Documentation\n\nWhen adding features, update all that apply: `docs/supported_entities.md` (new\nentity types), `docs/api-docs/api-docs.yml` (API changes), `README.md` (major\nfeatures), docstrings (all public classes/methods, reST format — `:param:`,\n`:return:`, `:raises:`), and `docs/samples/` (complex features).\n\nDo not update `CHANGELOG.md` in a PR: current-release entries are generated\nfrom merged PRs before each version bump, and per-PR edits create merge\nconflicts.\n\nTerminology: use \"threshold\", not \"cutoff\"; use ISO 639-1 language codes in\ndocs and configuration examples.\n\n## Code Review Guidelines\n\n- Only comment with HIGH CONFIDENCE (>80%) that an issue exists; be concise and\n  actionable — cite the line and propose the concrete fix.\n- Check for existing patterns and helpers in the codebase before suggesting new\n  approaches.\n- Severity: 🔴 security/PII leakage and correctness → 🟡 performance,\n  cross-component breaks, missing tests → 💡 code quality.\n\n**Do not flag** (automated tools own these): formatting, line length, import\norder (Ruff); type-hint style (`List[str]` vs `list[str]`); style preferences\nor speculative abstractions that don't fix bugs or improve accuracy.\n\n## Repository Context\n\n- **Python** `>=3.10,<3.15` — code must run on every version in range.\n- **uv** for dependency management (not pip/Poetry); each package commits a\n  `uv.lock`. Whenever a package's `pyproject.toml` dependencies change,\n  regenerate and commit that package's `uv.lock` in the same change\n  (`cd <package> && uv lock`) — CI installs with `uv sync --locked` and fails\n  on drift.\n- **Ruff** for linting and formatting; **spaCy** as the default NLP engine\n  (swappable via provider pattern); **Docker** images on\n  `ghcr.io/data-privacy-stack`.\n\n```bash\n# Setup and test (per package)\ncd presidio-analyzer\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg  # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n\n# E2E\ndocker compose up --build -d && cd e2e-tests && pytest -v\n```\n\nReference docs: `CONTRIBUTING.md`, `docs/development.md`,\n`docs/analyzer/adding_recognizers.md`, `docs/analyzer/developing_recognizers.md`,\n`docs/anonymizer/adding_operators.md`.\n","CLAUDE.md":"# Claude Code guidelines for Presidio\n\n@AGENTS.md\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/plugin.json)"},"files":{"AGENTS.md":"# Presidio — Agent Guidelines\n\nPresidio is a Python SDK for detecting (presidio-analyzer) and anonymizing\n(presidio-anonymizer) PII in text and images, plus CLI, structured-data, and\nimage-redaction components. It is a widely used **library**: users depend on\ncurrent detection behavior, and configuration files written years ago must keep\nworking. Correctness and backward compatibility outrank cleverness.\n\nThe review-side versions of these rules — which the Copilot PR review agent\nalso enforces — live in `.github/copilot-instructions.md` and\n`.github/instructions/*.instructions.md`. Follow them at authoring time so the\nreview finds nothing.\n\n## Working in this repo\n\n```bash\ncd presidio-analyzer            # or presidio-anonymizer, presidio-cli, ...\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg   # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n```\n\n- Python `>=3.10,<3.15`; code must run on every version in range.\n- Dependencies are managed with **uv**, not pip/Poetry. If you touch a\n  package's `pyproject.toml` dependencies, run `uv lock` in that package and\n  commit the updated `uv.lock` in the same change — CI fails on drift.\n- Do not edit `CHANGELOG.md`; release entries are generated from merged PRs.\n- Never log PII values (`entity.text`) — only entity types and positions.\n- Modules that process records are stateless; do not add state.\n- Terminology: \"threshold\", not \"cutoff\"; ISO 639-1 language codes everywhere.\n\n## Adding a PII recognizer\n\nThe full rulebook — score bands, context-word rules, validation-hook\nsemantics, the configuration-path test template, and the test-quality bar —\nis `.github/instructions/recognizers.instructions.md`. **Read it before\nstarting**; those rules apply at authoring time, not just in review. The\nworkflow, in order:\n\n1. **Place and name it** under `predefined_recognizers/`: full lowercase\n   country name for new country directories (`south_africa`, not `za`;\n   don't imitate the pre-existing short forms `us`/`uk`/`thai`), or\n   `generic/`, `nlp_engine_recognizers/`, `ner/`, `third_party/` as\n   appropriate.\n2. **Use ISO 639-1 language codes** (`ko` for Korean, never `kr`) — a\n   mismatch loads nothing, silently.\n3. **Make the constructor loader-compatible**: accept the YAML loader's\n   kwargs (`name`, `supported_entity`, `context`, ...) and forward them to\n   the base class, or the recognizer crashes the whole registry the moment a\n   user enables it.\n4. **Design the pattern for accuracy first** — this is the top review\n   priority: as specific as the format allows, score calibrated to the\n   pattern alone, unambiguous context words, the correct checksum if one\n   exists (and none invented if it doesn't), and the pattern's source\n   documented in the docstring, preferably an official specification.\n5. **Register it everywhere**: exports in `predefined_recognizers/__init__.py`\n   *and* the country/category `__init__.py`; an entry in\n   `conf/default_recognizers.yaml` (country-specific ships `enabled: false`);\n   a row in `docs/supported_entities.md`.\n6. **Write the configuration-path test** — the most-missed step and the one\n   that matters most: enable the recognizer in a YAML config, load it through\n   `RecognizerRegistryProvider`, and assert detection (template in the\n   instructions file). Non-English recognizers must set the top-level\n   `supported_languages` in the test config — it defaults to `[\"en\"]` and\n   silently filters everything else.\n\nWhen **modifying** an existing recognizer: changed patterns, scores, or context\nchange detection results for existing users — state that in the PR description,\nand never change an existing recognizer as a side effect of adding a new one.\n\n## Changing the YAML configuration layer\n\nThe rulebook for the pydantic models in `presidio_analyzer/input_validation/`\nis `.github/instructions/yaml-config.instructions.md` — **read it before\ntouching the layer**. The short version:\n\n- Constructor parameters and schema fields must never drift apart: a\n  YAML-settable kwarg without a matching pydantic field is silently dropped\n  today. Model-specific kwargs need a dedicated config model registered in\n  `CONFIG_MODEL_MAP`.\n- Choose `extra` deliberately (`forbid` fails fast, `allow` passes through);\n  pass-through models dump with `exclude_none=True` so YAML omissions keep\n  constructor defaults.\n- Validate at parse time with actionable messages, and never break existing\n  YAML — legacy singular fields, bare-string entries, and inferred `type` all\n  stay supported.\n- Test through `RecognizerRegistryProvider`, not just the pydantic model:\n  prove new fields reach the constructed object and assert error *messages*\n  for invalid YAML.\n\n## General engineering rules\n\n- **Declare behavior changes.** Any edit outside a brand-new file needs the PR\n  description to say what existing behavior changes. Defaults on shared base\n  classes, properties on abstract interfaces, and anything altering returned\n  entities or scores all count, even with no signature change.\n- **Explainability**: anything that changes how a score is derived must be\n  reflected in `AnalysisExplanation`.\n- **Component boundaries**: data flows Analyzer → Anonymizer → Output; import\n  public interfaces, never another component's internals; shared models\n  (`RecognizerResult`, `OperatorConfig`) are contracts — update all consumers\n  in the same changeset.\n- **Anonymizer operators**: non-reversible by default — no deterministic\n  hashing (rainbow tables), unpredictable replacement values, no preserved PII\n  characteristics. Deterministic or format-preserving output is sometimes a\n  hard requirement (e.g. referential integrity across a dataset); support it as\n  an explicit, documented opt-in, never as the default behavior.\n- **Security**: never log PII values; validate untrusted inputs before use\n  (user-supplied regexes before compilation, file paths, API payloads); no\n  hardcoded secrets; no unsafe deserialization of untrusted models or pickles.\n- **Performance**: no catastrophic regex backtracking (test long adversarial\n  inputs); cache compiled regexes; batch NLP with `nlp.pipe`.\n- **Docs move with code**: `docs/supported_entities.md` for entities,\n  `docs/api-docs/api-docs.yml` for API changes, reST docstrings on public\n  APIs, samples for complex features.\n",".github/copilot-instructions.md":"# Presidio Development & Review Instructions\n\nPresidio is a Python-based data protection and de-identification SDK with\nmultiple components for detecting and anonymizing PII (Personally Identifiable\nInformation) in text and images.\n\nDomain-specific rules live in path-scoped instruction files and apply on top of\nthis file when a change touches the matching paths:\n\n- `.github/instructions/recognizers.instructions.md` — adding or modifying PII\n  recognizers.\n- `.github/instructions/yaml-config.instructions.md` — the pydantic layer that\n  translates YAML configuration into Presidio instances.\n\n## Core Philosophy\n\n**Data privacy is paramount.** This is a PII detection and anonymization system\nused in sensitive contexts; security and correctness are non-negotiable.\n\n- **Accuracy first**: false negatives (missed PII) and false positives\n  (incorrect detections) both damage trust.\n- **Security by default**: never log PII values, use non-reversible\n  anonymization, validate all inputs.\n- **Presidio is a library**: changes to shared code alter results for users who\n  wrote no new code. Backward compatibility is the prime directive.\n- **Stateless design**: modules that process records are stateless for\n  scalability — avoid adding state.\n- **Cross-component awareness**: Presidio is a multi-component system; changes\n  ripple across boundaries.\n- **Documentation integrity**: code and docs must stay synchronized — outdated\n  docs are dangerous.\n\n## Backward Compatibility\n\nBefore changing anything outside a brand-new file, the PR description must\nstate what existing behavior changes. These count as behavior changes even\nwithout a signature change:\n\n- Default values on shared base classes (`None` to `[]` changes truthiness for\n  every subclass).\n- Properties on abstract interfaces — custom implementations inherit the new\n  default and may break.\n- Anything altering which entities are returned, or their scores, for text that\n  previously worked.\n\nPrefer additive changes: new parameters get defaults preserving current\nbehavior; public APIs are never broken without a deprecation path.\n\n**Surface new scoring inputs in explainability.** Anything that changes how a\nscore is derived (context, negative context, thresholds) must be reflected in\n`AnalysisExplanation`, or users cannot tell why a result scored as it did.\n\n**Prefer warnings over exceptions when the caller cannot fix the condition.**\nRaising on a configuration a user did not write turns a degraded result into a\nhard failure. Where a lookup falls back to a default, add a debug log so the\nfallback is discoverable.\n\n**Prefer a property on the base class over a maintained list of class names.**\nLists drift as classes are added, and users installing from PyPI cannot extend\nthem.\n\n## Cross-Component Changes\n\nData flows one way: Analyzer → Anonymizer → Output. Downstream components\n(CLI, structured, image-redactor) consume analyzer/anonymizer, never the\nreverse.\n\n- Shared data models (`RecognizerResult`, `OperatorConfig`) are contracts —\n  changes require coordinated updates across all consumers, in the same\n  changeset.\n- Reuse by importing from shared modules, not by copying code across\n  components. If multiple components need a feature, extract it to a common\n  location.\n- Respect boundaries: a component imports another's public interface, never its\n  internals (e.g. the anonymizer must not import\n  `presidio_analyzer.predefined_recognizers`).\n- Registry and provider patterns exist to decouple components — bypassing them\n  creates hidden dependencies.\n- Test the complete integration path (unit, integration, and e2e), not just\n  isolated components.\n\n## Security & Privacy\n\nAlways flag:\n\n- **PII leakage in logs, errors, or debug output** — log entity types and\n  positions, never `entity.text`.\n- **Reversible or weak anonymization** — deterministic hashing is reversible\n  via rainbow tables; use random/unpredictable replacement values that don't\n  preserve PII characteristics.\n- Regex injection: user-provided patterns must be validated before compilation.\n- Hardcoded secrets or credentials; unsafe deserialization (pickle, untrusted\n  models); command injection; path traversal; missing input validation on API\n  endpoints (including unbounded input sizes).\n\n## Performance\n\n- Avoid catastrophic regex backtracking (`(a+)+b` is O(2^n) on `aaaa...b`);\n  test patterns against long adversarial strings.\n- Cache compiled regexes; don't recompile per call.\n- Batch NLP processing (`nlp.pipe`) instead of per-text calls; load models\n  once and reuse.\n- Flag O(n²) where O(n) exists, blocking I/O on API paths, and loading entire\n  datasets into memory.\n\n## Testing Standards\n\n- Test names describe behavior:\n  `test_when_invalid_checksum_then_no_match`, not `test_case2`.\n- Assert exact expected values, not ranges — a range assertion passes even when\n  the logic producing the value breaks.\n- Cover true positives, true negatives, edge cases, and values embedded in\n  surrounding text; validate exact boundaries, not just types.\n- Fix random seeds for non-deterministic NLP/ML tests.\n- Test behavior, not implementation details.\n\n## Documentation\n\nWhen adding features, update all that apply: `docs/supported_entities.md` (new\nentity types), `docs/api-docs/api-docs.yml` (API changes), `README.md` (major\nfeatures), docstrings (all public classes/methods, reST format — `:param:`,\n`:return:`, `:raises:`), and `docs/samples/` (complex features).\n\nDo not update `CHANGELOG.md` in a PR: current-release entries are generated\nfrom merged PRs before each version bump, and per-PR edits create merge\nconflicts.\n\nTerminology: use \"threshold\", not \"cutoff\"; use ISO 639-1 language codes in\ndocs and configuration examples.\n\n## Code Review Guidelines\n\n- Only comment with HIGH CONFIDENCE (>80%) that an issue exists; be concise and\n  actionable — cite the line and propose the concrete fix.\n- Check for existing patterns and helpers in the codebase before suggesting new\n  approaches.\n- Severity: 🔴 security/PII leakage and correctness → 🟡 performance,\n  cross-component breaks, missing tests → 💡 code quality.\n\n**Do not flag** (automated tools own these): formatting, line length, import\norder (Ruff); type-hint style (`List[str]` vs `list[str]`); style preferences\nor speculative abstractions that don't fix bugs or improve accuracy.\n\n## Repository Context\n\n- **Python** `>=3.10,<3.15` — code must run on every version in range.\n- **uv** for dependency management (not pip/Poetry); each package commits a\n  `uv.lock`. Whenever a package's `pyproject.toml` dependencies change,\n  regenerate and commit that package's `uv.lock` in the same change\n  (`cd <package> && uv lock`) — CI installs with `uv sync --locked` and fails\n  on drift.\n- **Ruff** for linting and formatting; **spaCy** as the default NLP engine\n  (swappable via provider pattern); **Docker** images on\n  `ghcr.io/data-privacy-stack`.\n\n```bash\n# Setup and test (per package)\ncd presidio-analyzer\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg  # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n\n# E2E\ndocker compose up --build -d && cd e2e-tests && pytest -v\n```\n\nReference docs: `CONTRIBUTING.md`, `docs/development.md`,\n`docs/analyzer/adding_recognizers.md`, `docs/analyzer/developing_recognizers.md`,\n`docs/anonymizer/adding_operators.md`.\n","CLAUDE.md":"# Claude Code guidelines for Presidio\n\n@AGENTS.md\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/plugin.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Presidio — Agent Guidelines\n\nPresidio is a Python SDK for detecting (presidio-analyzer) and anonymizing\n(presidio-anonymizer) PII in text and images, plus CLI, structured-data, and\nimage-redaction components. It is a widely used **library**: users depend on\ncurrent detection behavior, and configuration files written years ago must keep\nworking. Correctness and backward compatibility outrank cleverness.\n\nThe review-side versions of these rules — which the Copilot PR review agent\nalso enforces — live in `.github/copilot-instructions.md` and\n`.github/instructions/*.instructions.md`. Follow them at authoring time so the\nreview finds nothing.\n\n## Working in this repo\n\n```bash\ncd presidio-analyzer            # or presidio-anonymizer, presidio-cli, ...\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg   # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n```\n\n- Python `>=3.10,<3.15`; code must run on every version in range.\n- Dependencies are managed with **uv**, not pip/Poetry. If you touch a\n  package's `pyproject.toml` dependencies, run `uv lock` in that package and\n  commit the updated `uv.lock` in the same change — CI fails on drift.\n- Do not edit `CHANGELOG.md`; release entries are generated from merged PRs.\n- Never log PII values (`entity.text`) — only entity types and positions.\n- Modules that process records are stateless; do not add state.\n- Terminology: \"threshold\", not \"cutoff\"; ISO 639-1 language codes everywhere.\n\n## Adding a PII recognizer\n\nThe full rulebook — score bands, context-word rules, validation-hook\nsemantics, the configuration-path test template, and the test-quality bar —\nis `.github/instructions/recognizers.instructions.md`. **Read it before\nstarting**; those rules apply at authoring time, not just in review. The\nworkflow, in order:\n\n1. **Place and name it** under `predefined_recognizers/`: full lowercase\n   country name for new country directories (`south_africa`, not `za`;\n   don't imitate the pre-existing short forms `us`/`uk`/`thai`), or\n   `generic/`, `nlp_engine_recognizers/`, `ner/`, `third_party/` as\n   appropriate.\n2. **Use ISO 639-1 language codes** (`ko` for Korean, never `kr`) — a\n   mismatch loads nothing, silently.\n3. **Make the constructor loader-compatible**: accept the YAML loader's\n   kwargs (`name`, `supported_entity`, `context`, ...) and forward them to\n   the base class, or the recognizer crashes the whole registry the moment a\n   user enables it.\n4. **Design the pattern for accuracy first** — this is the top review\n   priority: as specific as the format allows, score calibrated to the\n   pattern alone, unambiguous context words, the correct checksum if one\n   exists (and none invented if it doesn't), and the pattern's source\n   documented in the docstring, preferably an official specification.\n5. **Register it everywhere**: exports in `predefined_recognizers/__init__.py`\n   *and* the country/category `__init__.py`; an entry in\n   `conf/default_recognizers.yaml` (country-specific ships `enabled: false`);\n   a row in `docs/supported_entities.md`.\n6. **Write the configuration-path test** — the most-missed step and the one\n   that matters most: enable the recognizer in a YAML config, load it through\n   `RecognizerRegistryProvider`, and assert detection (template in the\n   instructions file). Non-English recognizers must set the top-level\n   `supported_languages` in the test config — it defaults to `[\"en\"]` and\n   silently filters everything else.\n\nWhen **modifying** an existing recognizer: changed patterns, scores, or context\nchange detection results for existing users — state that in the PR description,\nand never change an existing recognizer as a side effect of adding a new one.\n\n## Changing the YAML configuration layer\n\nThe rulebook for the pydantic models in `presidio_analyzer/input_validation/`\nis `.github/instructions/yaml-config.instructions.md` — **read it before\ntouching the layer**. The short version:\n\n- Constructor parameters and schema fields must never drift apart: a\n  YAML-settable kwarg without a matching pydantic field is silently dropped\n  today. Model-specific kwargs need a dedicated config model registered in\n  `CONFIG_MODEL_MAP`.\n- Choose `extra` deliberately (`forbid` fails fast, `allow` passes through);\n  pass-through models dump with `exclude_none=True` so YAML omissions keep\n  constructor defaults.\n- Validate at parse time with actionable messages, and never break existing\n  YAML — legacy singular fields, bare-string entries, and inferred `type` all\n  stay supported.\n- Test through `RecognizerRegistryProvider`, not just the pydantic model:\n  prove new fields reach the constructed object and assert error *messages*\n  for invalid YAML.\n\n## General engineering rules\n\n- **Declare behavior changes.** Any edit outside a brand-new file needs the PR\n  description to say what existing behavior changes. Defaults on shared base\n  classes, properties on abstract interfaces, and anything altering returned\n  entities or scores all count, even with no signature change.\n- **Explainability**: anything that changes how a score is derived must be\n  reflected in `AnalysisExplanation`.\n- **Component boundaries**: data flows Analyzer → Anonymizer → Output; import\n  public interfaces, never another component's internals; shared models\n  (`RecognizerResult`, `OperatorConfig`) are contracts — update all consumers\n  in the same changeset.\n- **Anonymizer operators**: non-reversible by default — no deterministic\n  hashing (rainbow tables), unpredictable replacement values, no preserved PII\n  characteristics. Deterministic or format-preserving output is sometimes a\n  hard requirement (e.g. referential integrity across a dataset); support it as\n  an explicit, documented opt-in, never as the default behavior.\n- **Security**: never log PII values; validate untrusted inputs before use\n  (user-supplied regexes before compilation, file paths, API payloads); no\n  hardcoded secrets; no unsafe deserialization of untrusted models or pickles.\n- **Performance**: no catastrophic regex backtracking (test long adversarial\n  inputs); cache compiled regexes; batch NLP with `nlp.pipe`.\n- **Docs move with code**: `docs/supported_entities.md` for entities,\n  `docs/api-docs/api-docs.yml` for API changes, reST docstrings on public\n  APIs, samples for complex features.\n","isInternal":false,"tokens":1476,"sizeBytes":6406},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# Claude Code guidelines for Presidio\n\n@AGENTS.md\n","isInternal":false,"tokens":14,"sizeBytes":50},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# Presidio Development & Review Instructions\n\nPresidio is a Python-based data protection and de-identification SDK with\nmultiple components for detecting and anonymizing PII (Personally Identifiable\nInformation) in text and images.\n\nDomain-specific rules live in path-scoped instruction files and apply on top of\nthis file when a change touches the matching paths:\n\n- `.github/instructions/recognizers.instructions.md` — adding or modifying PII\n  recognizers.\n- `.github/instructions/yaml-config.instructions.md` — the pydantic layer that\n  translates YAML configuration into Presidio instances.\n\n## Core Philosophy\n\n**Data privacy is paramount.** This is a PII detection and anonymization system\nused in sensitive contexts; security and correctness are non-negotiable.\n\n- **Accuracy first**: false negatives (missed PII) and false positives\n  (incorrect detections) both damage trust.\n- **Security by default**: never log PII values, use non-reversible\n  anonymization, validate all inputs.\n- **Presidio is a library**: changes to shared code alter results for users who\n  wrote no new code. Backward compatibility is the prime directive.\n- **Stateless design**: modules that process records are stateless for\n  scalability — avoid adding state.\n- **Cross-component awareness**: Presidio is a multi-component system; changes\n  ripple across boundaries.\n- **Documentation integrity**: code and docs must stay synchronized — outdated\n  docs are dangerous.\n\n## Backward Compatibility\n\nBefore changing anything outside a brand-new file, the PR description must\nstate what existing behavior changes. These count as behavior changes even\nwithout a signature change:\n\n- Default values on shared base classes (`None` to `[]` changes truthiness for\n  every subclass).\n- Properties on abstract interfaces — custom implementations inherit the new\n  default and may break.\n- Anything altering which entities are returned, or their scores, for text that\n  previously worked.\n\nPrefer additive changes: new parameters get defaults preserving current\nbehavior; public APIs are never broken without a deprecation path.\n\n**Surface new scoring inputs in explainability.** Anything that changes how a\nscore is derived (context, negative context, thresholds) must be reflected in\n`AnalysisExplanation`, or users cannot tell why a result scored as it did.\n\n**Prefer warnings over exceptions when the caller cannot fix the condition.**\nRaising on a configuration a user did not write turns a degraded result into a\nhard failure. Where a lookup falls back to a default, add a debug log so the\nfallback is discoverable.\n\n**Prefer a property on the base class over a maintained list of class names.**\nLists drift as classes are added, and users installing from PyPI cannot extend\nthem.\n\n## Cross-Component Changes\n\nData flows one way: Analyzer → Anonymizer → Output. Downstream components\n(CLI, structured, image-redactor) consume analyzer/anonymizer, never the\nreverse.\n\n- Shared data models (`RecognizerResult`, `OperatorConfig`) are contracts —\n  changes require coordinated updates across all consumers, in the same\n  changeset.\n- Reuse by importing from shared modules, not by copying code across\n  components. If multiple components need a feature, extract it to a common\n  location.\n- Respect boundaries: a component imports another's public interface, never its\n  internals (e.g. the anonymizer must not import\n  `presidio_analyzer.predefined_recognizers`).\n- Registry and provider patterns exist to decouple components — bypassing them\n  creates hidden dependencies.\n- Test the complete integration path (unit, integration, and e2e), not just\n  isolated components.\n\n## Security & Privacy\n\nAlways flag:\n\n- **PII leakage in logs, errors, or debug output** — log entity types and\n  positions, never `entity.text`.\n- **Reversible or weak anonymization** — deterministic hashing is reversible\n  via rainbow tables; use random/unpredictable replacement values that don't\n  preserve PII characteristics.\n- Regex injection: user-provided patterns must be validated before compilation.\n- Hardcoded secrets or credentials; unsafe deserialization (pickle, untrusted\n  models); command injection; path traversal; missing input validation on API\n  endpoints (including unbounded input sizes).\n\n## Performance\n\n- Avoid catastrophic regex backtracking (`(a+)+b` is O(2^n) on `aaaa...b`);\n  test patterns against long adversarial strings.\n- Cache compiled regexes; don't recompile per call.\n- Batch NLP processing (`nlp.pipe`) instead of per-text calls; load models\n  once and reuse.\n- Flag O(n²) where O(n) exists, blocking I/O on API paths, and loading entire\n  datasets into memory.\n\n## Testing Standards\n\n- Test names describe behavior:\n  `test_when_invalid_checksum_then_no_match`, not `test_case2`.\n- Assert exact expected values, not ranges — a range assertion passes even when\n  the logic producing the value breaks.\n- Cover true positives, true negatives, edge cases, and values embedded in\n  surrounding text; validate exact boundaries, not just types.\n- Fix random seeds for non-deterministic NLP/ML tests.\n- Test behavior, not implementation details.\n\n## Documentation\n\nWhen adding features, update all that apply: `docs/supported_entities.md` (new\nentity types), `docs/api-docs/api-docs.yml` (API changes), `README.md` (major\nfeatures), docstrings (all public classes/methods, reST format — `:param:`,\n`:return:`, `:raises:`), and `docs/samples/` (complex features).\n\nDo not update `CHANGELOG.md` in a PR: current-release entries are generated\nfrom merged PRs before each version bump, and per-PR edits create merge\nconflicts.\n\nTerminology: use \"threshold\", not \"cutoff\"; use ISO 639-1 language codes in\ndocs and configuration examples.\n\n## Code Review Guidelines\n\n- Only comment with HIGH CONFIDENCE (>80%) that an issue exists; be concise and\n  actionable — cite the line and propose the concrete fix.\n- Check for existing patterns and helpers in the codebase before suggesting new\n  approaches.\n- Severity: 🔴 security/PII leakage and correctness → 🟡 performance,\n  cross-component breaks, missing tests → 💡 code quality.\n\n**Do not flag** (automated tools own these): formatting, line length, import\norder (Ruff); type-hint style (`List[str]` vs `list[str]`); style preferences\nor speculative abstractions that don't fix bugs or improve accuracy.\n\n## Repository Context\n\n- **Python** `>=3.10,<3.15` — code must run on every version in range.\n- **uv** for dependency management (not pip/Poetry); each package commits a\n  `uv.lock`. Whenever a package's `pyproject.toml` dependencies change,\n  regenerate and commit that package's `uv.lock` in the same change\n  (`cd <package> && uv lock`) — CI installs with `uv sync --locked` and fails\n  on drift.\n- **Ruff** for linting and formatting; **spaCy** as the default NLP engine\n  (swappable via provider pattern); **Docker** images on\n  `ghcr.io/data-privacy-stack`.\n\n```bash\n# Setup and test (per package)\ncd presidio-analyzer\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg  # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n\n# E2E\ndocker compose up --build -d && cd e2e-tests && pytest -v\n```\n\nReference docs: `CONTRIBUTING.md`, `docs/development.md`,\n`docs/analyzer/adding_recognizers.md`, `docs/analyzer/developing_recognizers.md`,\n`docs/anonymizer/adding_operators.md`.\n","isInternal":false,"tokens":1688,"sizeBytes":7425},{"name":"marketplace.json","path":".claude-plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/marketplace.json","title":"Claude Plugin Marketplace Catalog","category":"marketplace","format":"json","content":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/marketplace.json)","tokens":300,"sizeBytes":197},{"name":"plugin.json","path":".claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":183},{"name":"mcp.json","path":".cursor/mcp.json","rawUrl":"https://raw.githubusercontent.com/microsoft/presidio/HEAD/.cursor/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.cursor/mcp.json)","tokens":300,"sizeBytes":176}],"systemPromptSnippet":"<yakaai_skills repo=\"microsoft/presidio\">\n<!-- File: AGENTS.md (Tokens: ~1476 | Category: root-instruction) -->\n# Presidio — Agent Guidelines\n\nPresidio is a Python SDK for detecting (presidio-analyzer) and anonymizing\n(presidio-anonymizer) PII in text and images, plus CLI, structured-data, and\nimage-redaction components. It is a widely used **library**: users depend on\ncurrent detection behavior, and configuration files written years ago must keep\nworking. Correctness and backward compatibility outrank cleverness.\n\nThe review-side versions of these rules — which the Copilot PR review agent\nalso enforces — live in `.github/copilot-instructions.md` and\n`.github/instructions/*.instructions.md`. Follow them at authoring time so the\nreview finds nothing.\n\n## Working in this repo\n\n```bash\ncd presidio-analyzer            # or presidio-anonymizer, presidio-cli, ...\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg   # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n```\n\n- Python `>=3.10,<3.15`; code must run on every version in range.\n- Dependencies are managed with **uv**, not pip/Poetry. If you touch a\n  package's `pyproject.toml` dependencies, run `uv lock` in that package and\n  commit the updated `uv.lock` in the same change — CI fails on drift.\n- Do not edit `CHANGELOG.md`; release entries are generated from merged PRs.\n- Never log PII values (`entity.text`) — only entity types and positions.\n- Modules that process records are stateless; do not add state.\n- Terminology: \"threshold\", not \"cutoff\"; ISO 639-1 language codes everywhere.\n\n## Adding a PII recognizer\n\nThe full rulebook — score bands, context-word rules, validation-hook\nsemantics, the configuration-path test template, and the test-quality bar —\nis `.github/instructions/recognizers.instructions.md`. **Read it before\nstarting**; those rules apply at authoring time, not just in review. The\nworkflow, in order:\n\n1. **Place and name it** under `predefined_recognizers/`: full lowercase\n   country name for new country directories (`south_africa`, not `za`;\n   don't imitate the pre-existing short forms `us`/`uk`/`thai`), or\n   `generic/`, `nlp_engine_recognizers/`, `ner/`, `third_party/` as\n   appropriate.\n2. **Use ISO 639-1 language codes** (`ko` for Korean, never `kr`) — a\n   mismatch loads nothing, silently.\n3. **Make the constructor loader-compatible**: accept the YAML loader's\n   kwargs (`name`, `supported_entity`, `context`, ...) and forward them to\n   the base class, or the recognizer crashes the whole registry the moment a\n   user enables it.\n4. **Design the pattern for accuracy first** — this is the top review\n   priority: as specific as the format allows, score calibrated to the\n   pattern alone, unambiguous context words, the correct checksum if one\n   exists (and none invented if it doesn't), and the pattern's source\n   documented in the docstring, preferably an official specification.\n5. **Register it everywhere**: exports in `predefined_recognizers/__init__.py`\n   *and* the country/category `__init__.py`; an entry in\n   `conf/default_recognizers.yaml` (country-specific ships `enabled: false`);\n   a row in `docs/supported_entities.md`.\n6. **Write the configuration-path test** — the most-missed step and the one\n   that matters most: enable the recognizer in a YAML config, load it through\n   `RecognizerRegistryProvider`, and assert detection (template in the\n   instructions file). Non-English recognizers must set the top-level\n   `supported_languages` in the test config — it defaults to `[\"en\"]` and\n   silently filters everything else.\n\nWhen **modifying** an existing recognizer: changed patterns, scores, or context\nchange detection results for existing users — state that in the PR description,\nand never change an existing recognizer as a side effect of adding a new one.\n\n## Changing the YAML configuration layer\n\nThe rulebook for the pydantic models in `presidio_analyzer/input_validation/`\nis `.github/instructions/yaml-config.instructions.md` — **read it before\ntouching the layer**. The short version:\n\n- Constructor parameters and schema fields must never drift apart: a\n  YAML-settable kwarg without a matching pydantic field is silently dropped\n  today. Model-specific kwargs need a dedicated config model registered in\n  `CONFIG_MODEL_MAP`.\n- Choose `extra` deliberately (`forbid` fails fast, `allow` passes through);\n  pass-through models dump with `exclude_none=True` so YAML omissions keep\n  constructor defaults.\n- Validate at parse time with actionable messages, and never break existing\n  YAML — legacy singular fields, bare-string entries, and inferred `type` all\n  stay supported.\n- Test through `RecognizerRegistryProvider`, not just the pydantic model:\n  prove new fields reach the constructed object and assert error *messages*\n  for invalid YAML.\n\n## General engineering rules\n\n- **Declare behavior changes.** Any edit outside a brand-new file needs the PR\n  description to say what existing behavior changes. Defaults on shared base\n  classes, properties on abstract interfaces, and anything altering returned\n  entities or scores all count, even with no signature change.\n- **Explainability**: anything that changes how a score is derived must be\n  reflected in `AnalysisExplanation`.\n- **Component boundaries**: data flows Analyzer → Anonymizer → Output; import\n  public interfaces, never another component's internals; shared models\n  (`RecognizerResult`, `OperatorConfig`) are contracts — update all consumers\n  in the same changeset.\n- **Anonymizer operators**: non-reversible by default — no deterministic\n  hashing (rainbow tables), unpredictable replacement values, no preserved PII\n  characteristics. Deterministic or format-preserving output is sometimes a\n  hard requirement (e.g. referential integrity across a dataset); support it as\n  an explicit, documented opt-in, never as the default behavior.\n- **Security**: never log PII values; validate untrusted inputs before use\n  (user-supplied regexes before compilation, file paths, API payloads); no\n  hardcoded secrets; no unsafe deserialization of untrusted models or pickles.\n- **Performance**: no catastrophic regex backtracking (test long adversarial\n  inputs); cache compiled regexes; batch NLP with `nlp.pipe`.\n- **Docs move with code**: `docs/supported_entities.md` for entities,\n  `docs/api-docs/api-docs.yml` for API changes, reST docstrings on public\n  APIs, samples for complex features.\n\n<!-- File: CLAUDE.md (Tokens: ~14 | Category: claude-rule) -->\n# Claude Code guidelines for Presidio\n\n@AGENTS.md\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~1688 | Category: copilot-instructions) -->\n# Presidio Development & Review Instructions\n\nPresidio is a Python-based data protection and de-identification SDK with\nmultiple components for detecting and anonymizing PII (Personally Identifiable\nInformation) in text and images.\n\nDomain-specific rules live in path-scoped instruction files and apply on top of\nthis file when a change touches the matching paths:\n\n- `.github/instructions/recognizers.instructions.md` — adding or modifying PII\n  recognizers.\n- `.github/instructions/yaml-config.instructions.md` — the pydantic layer that\n  translates YAML configuration into Presidio instances.\n\n## Core Philosophy\n\n**Data privacy is paramount.** This is a PII detection and anonymization system\nused in sensitive contexts; security and correctness are non-negotiable.\n\n- **Accuracy first**: false negatives (missed PII) and false positives\n  (incorrect detections) both damage trust.\n- **Security by default**: never log PII values, use non-reversible\n  anonymization, validate all inputs.\n- **Presidio is a library**: changes to shared code alter results for users who\n  wrote no new code. Backward compatibility is the prime directive.\n- **Stateless design**: modules that process records are stateless for\n  scalability — avoid adding state.\n- **Cross-component awareness**: Presidio is a multi-component system; changes\n  ripple across boundaries.\n- **Documentation integrity**: code and docs must stay synchronized — outdated\n  docs are dangerous.\n\n## Backward Compatibility\n\nBefore changing anything outside a brand-new file, the PR description must\nstate what existing behavior changes. These count as behavior changes even\nwithout a signature change:\n\n- Default values on shared base classes (`None` to `[]` changes truthiness for\n  every subclass).\n- Properties on abstract interfaces — custom implementations inherit the new\n  default and may break.\n- Anything altering which entities are returned, or their scores, for text that\n  previously worked.\n\nPrefer additive changes: new parameters get defaults preserving current\nbehavior; public APIs are never broken without a deprecation path.\n\n**Surface new scoring inputs in explainability.** Anything that changes how a\nscore is derived (context, negative context, thresholds) must be reflected in\n`AnalysisExplanation`, or users cannot tell why a result scored as it did.\n\n**Prefer warnings over exceptions when the caller cannot fix the condition.**\nRaising on a configuration a user did not write turns a degraded result into a\nhard failure. Where a lookup falls back to a default, add a debug log so the\nfallback is discoverable.\n\n**Prefer a property on the base class over a maintained list of class names.**\nLists drift as classes are added, and users installing from PyPI cannot extend\nthem.\n\n## Cross-Component Changes\n\nData flows one way: Analyzer → Anonymizer → Output. Downstream components\n(CLI, structured, image-redactor) consume analyzer/anonymizer, never the\nreverse.\n\n- Shared data models (`RecognizerResult`, `OperatorConfig`) are contracts —\n  changes require coordinated updates across all consumers, in the same\n  changeset.\n- Reuse by importing from shared modules, not by copying code across\n  components. If multiple components need a feature, extract it to a common\n  location.\n- Respect boundaries: a component imports another's public interface, never its\n  internals (e.g. the anonymizer must not import\n  `presidio_analyzer.predefined_recognizers`).\n- Registry and provider patterns exist to decouple components — bypassing them\n  creates hidden dependencies.\n- Test the complete integration path (unit, integration, and e2e), not just\n  isolated components.\n\n## Security & Privacy\n\nAlways flag:\n\n- **PII leakage in logs, errors, or debug output** — log entity types and\n  positions, never `entity.text`.\n- **Reversible or weak anonymization** — deterministic hashing is reversible\n  via rainbow tables; use random/unpredictable replacement values that don't\n  preserve PII characteristics.\n- Regex injection: user-provided patterns must be validated before compilation.\n- Hardcoded secrets or credentials; unsafe deserialization (pickle, untrusted\n  models); command injection; path traversal; missing input validation on API\n  endpoints (including unbounded input sizes).\n\n## Performance\n\n- Avoid catastrophic regex backtracking (`(a+)+b` is O(2^n) on `aaaa...b`);\n  test patterns against long adversarial strings.\n- Cache compiled regexes; don't recompile per call.\n- Batch NLP processing (`nlp.pipe`) instead of per-text calls; load models\n  once and reuse.\n- Flag O(n²) where O(n) exists, blocking I/O on API paths, and loading entire\n  datasets into memory.\n\n## Testing Standards\n\n- Test names describe behavior:\n  `test_when_invalid_checksum_then_no_match`, not `test_case2`.\n- Assert exact expected values, not ranges — a range assertion passes even when\n  the logic producing the value breaks.\n- Cover true positives, true negatives, edge cases, and values embedded in\n  surrounding text; validate exact boundaries, not just types.\n- Fix random seeds for non-deterministic NLP/ML tests.\n- Test behavior, not implementation details.\n\n## Documentation\n\nWhen adding features, update all that apply: `docs/supported_entities.md` (new\nentity types), `docs/api-docs/api-docs.yml` (API changes), `README.md` (major\nfeatures), docstrings (all public classes/methods, reST format — `:param:`,\n`:return:`, `:raises:`), and `docs/samples/` (complex features).\n\nDo not update `CHANGELOG.md` in a PR: current-release entries are generated\nfrom merged PRs before each version bump, and per-PR edits create merge\nconflicts.\n\nTerminology: use \"threshold\", not \"cutoff\"; use ISO 639-1 language codes in\ndocs and configuration examples.\n\n## Code Review Guidelines\n\n- Only comment with HIGH CONFIDENCE (>80%) that an issue exists; be concise and\n  actionable — cite the line and propose the concrete fix.\n- Check for existing patterns and helpers in the codebase before suggesting new\n  approaches.\n- Severity: 🔴 security/PII leakage and correctness → 🟡 performance,\n  cross-component breaks, missing tests → 💡 code quality.\n\n**Do not flag** (automated tools own these): formatting, line length, import\norder (Ruff); type-hint style (`List[str]` vs `list[str]`); style preferences\nor speculative abstractions that don't fix bugs or improve accuracy.\n\n## Repository Context\n\n- **Python** `>=3.10,<3.15` — code must run on every version in range.\n- **uv** for dependency management (not pip/Poetry); each package commits a\n  `uv.lock`. Whenever a package's `pyproject.toml` dependencies change,\n  regenerate and commit that package's `uv.lock` in the same change\n  (`cd <package> && uv lock`) — CI installs with `uv sync --locked` and fails\n  on drift.\n- **Ruff** for linting and formatting; **spaCy** as the default NLP engine\n  (swappable via provider pattern); **Docker** images on\n  `ghcr.io/data-privacy-stack`.\n\n```bash\n# Setup and test (per package)\ncd presidio-analyzer\nuv sync --locked --all-extras --group dev\nuv run python -m spacy download en_core_web_lg  # analyzer/CLI only\nuv run pytest -xvv\nuv run ruff check . && uv run ruff format .\n\n# E2E\ndocker compose up --build -d && cd e2e-tests && pytest -v\n```\n\nReference docs: `CONTRIBUTING.md`, `docs/development.md`,\n`docs/analyzer/adding_recognizers.md`, `docs/analyzer/developing_recognizers.md`,\n`docs/anonymizer/adding_operators.md`.\n\n<!-- File: .claude-plugin/marketplace.json (Tokens: ~300 | Category: marketplace) -->\n# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/marketplace.json)\n\n<!-- File: .claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.claude-plugin/plugin.json)\n\n<!-- File: .cursor/mcp.json (Tokens: ~300 | Category: mcp-config) -->\n# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/microsoft/presidio/HEAD/.cursor/mcp.json)\n</yakaai_skills>"}