Skip to content
Architecture/architecture/adapters/
Architecture contents

05 · Adapters

The core knows what a secret is. Something has to go and get the text.

Six packages that fetch text, hand it to the core and carry the answer back. They decide nothing.

The problem it solves

A copied example is a fork you now own

The core repository ships worked examples of wiring a logger or a tracer into the scanner. You could copy the file. From that moment you owned it: no version, no changelog, no notice when the host SDK's contract moved, and no way for the project to fix wiring it had written itself.

Before

Copy pino-redact.mjs out of the examples folder. It works today. Nobody tells you when pino's next major changes the hook signature.

Now

npm install @redact-secret/adapter-pino. A declared pino range, tested at both ends, with its own changelog inside the tarball.

This repository exists to close that gap, without moving the wiring into the core.

Where they sit

Between your host and the engine

Your hostA pino logger, an OpenTelemetry span, a Python log record, an MCP tool result, a model prompt.
the adapter carries the text in

The Redact Secret core

It decides what a secret is. The adapter does not.

and carries the answer back out
The same host, sanitizedThe log line, the span attribute or the tool result goes on to its destination with nothing secret in it.

The packages

Six of them, on two registries

@redact-secret/adapter

npm · 0.1.2Released

The shared base everything else is built on: one primitive for masking a string, and the bounded walker that finds strings inside nested objects. Install it directly only when writing your own integration.

@redact-secret/adapter-pino

npm · 0.1.1 · pino ^10.0.0Released

Redacts by value, and works alongside pino's own path-based redact. pino cannot see a token inside a message string or an error message; this can.

@redact-secret/adapter-otel

npm · 0.1.1 · @opentelemetry/sdk-trace-base ^2.0.0Released

Every string and string-array attribute on a span and its events, redacted before the span reaches the next processor. Attribute names are not allowlisted, so OpenInference and GenAI conventions are covered without hardcoding either.

@redact-secret/adapter-ai-context

npm · 0.1.0-alpha.1Alpha

A framework-neutral boundary for AI work: user input, tool results, a constructed context and streamed text, sanitized before any of it reaches a model. It names no model vendor, agent framework or transport.

@redact-secret/adapter-mcp

npm · 0.1.0-alpha.1Alpha

The Model Context Protocol boundary: a tool's result, optionally its arguments, and what a client reads with resources/read. A thin specialization of the package above, adding only the MCP shape. It imports no MCP SDK, even for types.

redact-secret-adapters

PyPI · 0.1.0 · logging filter · [otel] extraReleased

Python's standard library has no value-based redaction at all. This filter adds it, and the [otel] extra covers spans.

A masking-callback host such as Langfuse needs no dedicated package: the shared walker is the whole integration.

Versions and host ranges were read from the npm and PyPI registries on 2026-09-28.

The design rule

When in doubt, print a marker

Every adapter shares one primitive for masking a string, and that primitive never lets an error put text on the wire. These markers are public API: they are what a host sees, and they change only in a major version.

MarkerWhen
[REDACTED:BLOCKED]A block finding. The entire leaf is replaced, not just the matched span.
[REDACTED:ERROR]Any failure inside the core call, including an uninitialized core. Never the original text, and never the error's own message.
[REDACTED:LIMIT_EXCEEDED]A value past a walk budget. It is never scanned, and never passed through unmasked.
[REDACTED:CYCLE]A self-referencing object.

The budgets

8max depth
1,000max array length
200max object keys
5,000max total leaves

Plus a 200,000-character cap per string. Elements and keys beyond a limit are dropped, not passed through. Every bound is overridable per call.

Why it stays small

Four things from the core, and nothing else

initialize()
Load the engine.
scanAndRedact()
And the shape of what it returns.
findings
As an array.
finding.action
Whether it is block or warn.

That surface is what the declared compatibility range protects. Because these packages are written in TypeScript against the core's own exported types, a change to it fails the build rather than degrading silently.

What “supported” means here

A range you can check, not a guess

Every published adapter states the host range it supports and runs a test against a real instance of that host, at both ends of the declared range, in CI.

AdapterDeclared rangeVerified by
adapter-pinopino ^10.0.0a real pino logger writing to a captured stream
adapter-otel@opentelemetry/sdk-trace-base ^2.0.0a real span passed through onEnd
Python loggingCPython >=3.10a real logger with the filter attached
Python otelopentelemetry-sdk <2,>=1.16.0a real span through a real tracer provider

A pino major outside the declared range is deliberately not claimed. It may work, but it is untested, and the core holds its detectors to the same rule.

Being honest

What is not here

Sources. README.md and ARCHITECTURE.md in redact-secret-adapters, plus each package's own README and changelog. Versions were read from the npm and PyPI registries on 2026-09-28, not from the repository.