Agent transcripts are durable and frequently leave your infrastructure: they are stored, replayed, and sent to third-party model providers. Repost redacts credentials from event payloads by default, but redaction is a credential scrubber, not a privacy control. The boundary between the two is the single most important thing to understand before copying any payload into a transcript.
Redaction does not remove PII. Names, email addresses, phone numbers, postal addresses, card numbers, bank details, national IDs, IP addresses, and customer identifiers pass through verbatim. Detection is by credential key/header name only. It has no concept of personal data. Never treat a payload as safe to paste, log, or forward just because it came back "redacted."
What redaction covers#
Redaction is applied server-side, by default, on exactly two commands: events get and events diff, the only commands that return full headers and bodies. The CLI never receives the unredacted form unless you explicitly opt out (see below). Each response also lists the exact paths it touched in a redactions array.
Headers are redacted by name:
authorization proxy-authorization cookie set-cookie x-api-key x-api-token
stripe-signature x-hub-signature x-hub-signature-256 x-slack-signature
svix-signature webhook-signature x-signatureSignature headers keep their plain metadata (t, ts, timestamp) in clear text and tag only the signature itself, so you can still reason about timing:
"stripe-signature": ["t=1718061000,v1=[redacted:hmac:9f2a1c4d8b07]"]JSON-object body keys are redacted by name: password, token, secret, api_key / apikey, access_token, refresh_token, client_secret, and any key whose name contains secret or token. Redaction recurses into nested objects.
Each redacted value becomes a deterministic tag:
[redacted:hmac:9f2a1c4d8b07]The tag is the first 12 hex characters of an org-scoped HMAC of the value. It is stable for the same value within an organization: identical secrets produce identical tags, so you can correlate "same credential" across events without ever seeing the secret. It is not reversible and differs across organizations.
Every response names the exact paths it touched in a redactions array, so you can audit what was removed:
"redactions": ["request.headers.authorization", "request.headers.stripe-signature"]What redaction does not cover#
The mechanism is a name-based credential filter. Everything outside that definition is returned in full. Assume each of these is present and act accordingly.
| Gap | Why it leaks | Example |
|---|---|---|
| All PII | No value-based or personal-data detection exists. | "email": "[email protected]" is returned as-is. |
| Secrets under innocuous keys | Only sensitive key names match. | {"data": "sk_live_51H..."}: key data is not sensitive, so the value stays. |
| Anything inside arrays | Redaction descends into objects, not array elements. | {"items": [{"token": "..."}]}: token inside the array is not redacted. |
| Non-object bodies | Only JSON objects are parsed and filtered. | Form-encoded, plain-text, XML, or a top-level JSON array body is shown raw, with no redaction at all. |
| URLs and paths | Not in scope. | Query strings and path segments are never redacted. |
The two highest-risk gaps are arrays and non-object bodies. A webhook that sends a JSON array, a form post, or secrets nested in a list receives no body redaction. Inspect the redactions array: if it is empty for a body you expected to be scrubbed, the payload was not an object. Treat the whole body as sensitive.
Opting out: the secrets scope#
events get --reveal-secrets and events get --as-fixture disable redaction and return full cleartext. Both require a token with the secrets scope; without it the CLI fails with forbidden_scope (exit 3) and emits nothing.
Reserve secrets for a narrow, deliberate need, such as reproducing a signature locally or building a fixture, and direct that output only to a trusted destination. Adding --reveal-secrets to "make debugging easier" routes raw credentials straight into the transcript. See Authentication & scopes.
Operating rules#
Never add --reveal-secrets or --as-fixture for convenience. If a token does not carry secrets, you cannot leak credentials through events get. Keep it that way.
Redaction will not catch it. Before a payload crosses a trust boundary (a logged transcript, a model provider, a ticket), summarize it, for example "a payment_intent.succeeded for in_123", instead of pasting it.
event_id, forward_id, status, latency, and response code are almost always enough to drive a decision and carry far less risk than a full body.
redactions tells you what was removed. An empty or short list means little was matched, often because the data was PII or lived in an array, not because the payload was clean.
If a body has to enter the transcript, remove PII yourself before writing it. Redaction is the floor, not the ceiling.
Redaction contract
- Applies by default on
events get/events diffonly (the only full-payload commands).redactions[]lists the exact paths removed. - Removes by name: credential + signature headers; JSON-object keys
password/token/secret/api_key/apikey/access_token/refresh_token/client_secretand any key containingsecret/token; recurses into nested objects. Signature headers keept/ts/timestamp. - Tag form
[redacted:hmac:<12hex>]: deterministic per (org, value), not reversible. - Does NOT remove: any PII; secrets under non-sensitive keys; anything inside arrays; non-object bodies (form/text/XML/top-level array → raw); URLs/paths.
--reveal-secrets/--as-fixture→ full cleartext, requiressecretsscope.- Rule: treat every body as PII-bearing; emit IDs/metadata, not payloads; scrub before persisting; never opt out for convenience.