Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

354 Commits

Folders and files

NameName
Last commit message
Last commit date

stella anonymize

Local PII detection and anonymization for text.

Website · Issues · npm · PyPI · Discord

npmPyPICILicense: Apache-2.0Discord

stella anonymize is an open-source, local-first PII redaction toolkit for legal and regulated workflows. Detection and replacement are implemented in a shared Rust core, with bindings for Node.js, Python, and browsers. The default pipeline is deterministic and makes no model or remote-service calls. Coverage varies by language, entity type, and document structure.

No detector catches everything. Reversible placeholder replacement is pseudonymization, and its maps contain original PII; do not log or treat them as anonymous output. The default pipeline targets personal identifiers, not passwords, authentication tokens, API keys, or private cryptographic material. IP addresses, MAC addresses, and URLs require explicit opt-in capabilities.

Contributing to the project is welcome.

Quickstart

Node.js

npm install @stll/anonymize

Requires Node.js 20 or newer or Bun 1.4 or newer. Prebuilt native binaries ship for macOS (arm64, x64), glibc-based Linux (arm64, x64), and Windows (x64). Alpine Linux and other musl-based systems are not supported.

import{createPipeline,deanonymise}from"@stll/anonymize";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("Contact Alice Smith at alice@example.com.",);console.log(redaction.redactedText);// Contact [PERSON_1] at [EMAIL_ADDRESS_1].constoriginal=deanonymise(redaction.redactedText,redaction.redactionMap);console.log(original);// Contact Alice Smith at alice@example.com.

Create the pipeline once and reuse it. Select one language, an exact combination such as { language: ["cs", "en"] }, or { language: "all" }. Supported codes are cs, de, en, es, fr, hu, it, lv, pl, pt-br, ro, sk, and sv. The factory uses a bundled prepared artifact when one matches and otherwise prepares the exact requested scope on first use. The Node package guide covers sessions, custom detections, operators, diagnostics, and prepared packages; the capability manifest is the exact list of public runtime surfaces and entity types.

Browser

npm install @stll/anonymize-wasm
import{createPipeline}from"@stll/anonymize-wasm";constpipeline=awaitcreatePipeline({language: "en"});const{ redaction }=pipeline.redactText("A contract signed by Alice Smith.");

The browser build is single-threaded and works without cross-origin isolation, SharedArrayBuffer, or a worker. Vite applications can use the package helper to emit the WebAssembly module and prepared data. See the browser guide.

Python

uv add stella-anonymize-core
# or: pip install stella-anonymize-core
importstella_anonymizeasanonymizepipeline=anonymize.create_pipeline(language="en", warmup="lazy-regex")
result=pipeline.redact_text(
"Contact Alice Smith at alice@example.com."
)
print(result.redaction.redacted_text)

Prebuilt Python 3.11+ wheels target manylinux glibc x64/aarch64, macOS x64/arm64, and Windows x64. The Python guide covers sessions, encrypted archives, caller detections, DOCX, and PDF APIs.

CLI

echo"Contact Alice Smith at alice@example.com"| npx @stll/anonymize-cli
# Contact [PERSON_1] at [EMAIL_ADDRESS_1]

The anonymize command reads stdin, files, or directory trees. It also supports reversible keys and DOCX/PDF workflows:

npx @stll/anonymize-cli -k contract.key.json -o contract.anon.txt contract.txt
npx @stll/anonymize-cli -d contract.key.json contract.anon.txt

Raw --key export is Linux-only and fails closed on other platforms because the CLI cannot verify owner-only filesystem ACLs.

See the CLI reference for batch processing, selective restoration, document commands, JSON output, and exit codes.

Local MCP server

@stll/anonymize-mcp exposes path-only tools over stdio. Tool arguments contain filesystem paths rather than document text, and results contain aggregate status rather than document contents or plaintext mappings.

{
"mcpServers": {
"stella-anonymize": {
"command": "npx",
"args": [
"-y",
"@stll/anonymize-mcp",
"--root",
"/absolute/path/to/workspace"
]
}
}
}

The server requires Node.js 20+. It supports text, DOCX, PDF, and provider-neutral external-detection sidecars for text. Encrypted durable sessions are optional and currently limited to macOS and Linux. PDF tools need local Poppler and Tesseract installations; their executable paths can be set at server startup. Read the MCP guide before enabling durable sessions or document tools; it defines path, permission, key, archive, and failure boundaries.

Document support

DOCX

DOCX extraction, anonymization, and restoration are available in Node.js and Python, and through the CLI and local MCP server. The adapters preserve the supported Word structures and return a coverage inventory for known content outside the rewrite surface. The default require-full policy fails closed on coverage gaps; partial rewrites require explicit opt-in.

The DOCX never stores the plaintext redaction mapping. Reversible workflows use an application-owned session and, when persisted, an encrypted session archive. Signed documents, tracked revisions, external relationship targets, and other package features have explicit restrictions. See @stll/anonymize-docx for the complete coverage contract.

PDF

PDF inspection is available in Node.js, Python, and WASM. Node.js and Python both expose the destructive raster contract, which requires complete rendered page pixels, OCR text, and glyph geometry. The Node.js package can produce those observations with separately installed Poppler and Tesseract; the CLI and MCP server use that adapter. Python callers must supply observations and pixels from their own renderer/OCR boundary.

The output is a new image-only PDF. Source PDF objects are not copied and black rectangles are not layered over recoverable content. This removes searchability, accessibility, links, forms, signatures, metadata, attachments, and other interactive features. Verification proves the fresh output structure and requested pixel rewrite; it cannot prove perfect OCR or PII detection recall. The certificate therefore never claims that the output is PII-free. See @stll/anonymize-pdf for the inspection, rendering, OCR, resource-limit, and verification contracts.

Packages

PackagePurpose
@stll/anonymizeNode.js SDK and native runtime
stella-anonymize-corePython bindings
@stll/anonymize-wasmBrowser/WASM runtime
@stll/anonymize-cliCommand-line text, DOCX, and PDF workflows
@stll/anonymize-mcpPath-only local MCP server
@stll/anonymize-docxStructure-aware DOCX adapter
@stll/anonymize-pdfPDF inspection and destructive raster anonymization
@stll/anonymize-dataPublished dictionaries and detector configuration
crates/anonymize-coreShared Rust core
crates/document-rules-coreStructured document rule engine

Platform-specific Node.js binary packages are installed automatically as optional dependencies of @stll/anonymize. Node.js and Bun use the same native binding; Bun 1.4 or newer is required. A clean macOS arm64 npm install from the packed artifacts uses about 80 MiB on disk; CI caps the packed SDK, data package, and every native sidecar combination at 85 MiB. Install @stll/anonymize-wasm separately only when you need the browser runtime.

Benchmarks

The deterministic pipeline is evaluated against publicly available tools on TAB-ECHR, RedactionBench, MEDDOCAN, MultiGraSCCo, and German Legal Entity Recognition. Tracks use different task semantics, and synthetic scores are not necessarily representative or directly comparable. Read the methodology, browse the aggregate results, or follow the reproduction guide.

Development

bun install --frozen-lockfile
bun run build
bun run lint
bun run format:check
bun run typecheck
bun run test
bun run check:version

Read the contributor guide for prerequisites, focused checks, architecture pointers, changesets, and the sensitive-fixture policy. A CLA check runs on pull requests.

License

Apache-2.0. See LICENSE.

About

Anonymization pipeline for sensitive text. Deterministic, local-first, fast.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages