Quick Start
1
Zero config — scrubbing is on by default
2
Opt out per bot
3
Bring your own redactor (e.g. add PII)
What Gets Masked
Two things are masked before a reply leaves the process: every value registered viaregister_secret_for_redaction (all resolved gateway credentials, masked by exact value) plus any token matching a narrow credential-shape pattern.
Personal data (PII) is deliberately out of scope for the built-in scrub — the shape patterns stay narrow so ordinary text is never over-redacted. Layer PII on with a custom redactor (see below).
How It Works
The scrub runs after everyMESSAGE_SENDING hook, so a hook cannot re-introduce a secret after your own logic runs.
Which Paths Are Covered
Every path that dispatches text to a chat user is scrubbed.The reply seam runs the scrub last — after any
MESSAGE_SENDING hook. Streaming edits bypass the reply seam, so both the rolling draft and the final answer are scrubbed in the streamer, before text-limit truncation, so a [REDACTED] mask is never cut across the length boundary.Custom Redactor
Inject anOutboundRedactor to add a policy the core scrub does not cover — PII, a company-internal token pattern, and so on.
OutboundRedactor is a @runtime_checkable protocol with one method, redact(self, text: str) -> str. The injected redactor wins over the core primitive. It must return a str — any non-str return is ignored and the core redact_outbound runs instead.
Opt-Out
Turn the scrub off for a single bot by setting one attribute.Ordinary Text Is Unchanged
The scrub is additive — absent a leak, ordinary text passes through untouched.Idempotency & Failure Modes
Scrubbing is idempotent — running it on already-scrubbed text is a no-op, so overlapping seams (finalize + reply hook) never double-mask. It is also best-effort: a scrubber exception is caught at every seam and the original text is delivered rather than dropped, so a bug in a custom redactor can never block delivery.Relationship to the Inbound Gate
Inbound and outbound are symmetric. The Inbound Message Gate filters what reaches the agent throughMESSAGE_RECEIVED; the outbound scrub filters what leaves the agent on the reply path. Together they bracket the agent on both sides.
Inbound Message Gate
Drop or redact incoming messages before the agent sees them.
Best Practices
Leave it on
Leave it on
The scrub is safe-by-default and additive — ordinary text is unchanged. Keep it on and opt out only when another layer already owns secret redaction.
Register any custom credential shape
Register any custom credential shape
The shape regex is deliberately narrow. For an unusual token format, register the value with
register_secret_for_redaction(value) so it is masked by exact value even when the shape patterns miss it.Layer PII on top with a custom OutboundRedactor
Layer PII on top with a custom OutboundRedactor
Don’t disable the core scrub to add PII masking — wrap it. Call
redact_outbound(text) first inside your redact method, then apply your own rules.Prefer scrubbing at the source for high-volume tool output
Prefer scrubbing at the source for high-volume tool output
For a tool that emits large or frequent output, scrub at the tool boundary with a guardrail — cheaper than scrubbing every reply. See Redact Tool Output.
Related
Inbound Message Gate
The symmetric inbound filter on
MESSAGE_RECEIVED.Gateway Secret References
Load credentials from files, env vars, or secret managers.
Hook Events
MESSAGE_SENDING and the full hook event reference.Redact Tool Output
Scrub secrets at the tool boundary before they reach a reply.

