Transcript Redactor Claude Code mod: a Claude Code transcript redactor
Swaps API keys and passwords for stable placeholders before Claude reads them, and restores them for local tools.
Permissions
- Reads filesCan read files and list directories on your machine ($.fs.read / list / stat / exists).
- Intercepts tool callsSees every tool call Claude makes (tool.call / tool.check) and could block or change it.
- Reads your promptsCan see what you type and the conversation transcript (prompt.* / session.append / session.messages).
- Changes the UIDraws into the Claude Code interface: bands, panes, status text, toasts (ui.render / $.ui.*).
- tested with
- v2.1.307
- last tested
- requires
- Claude Code ≥ 2.1.287
- surfaces
- toast, transcript
- source
- Ray Amjad (ray-amjad) (MIT)
Install inside Claude Code:
/plugin install transcript-redactor --marketplace ray-amjad/claude-code-modsWhat does this mod do?
This Claude Code transcript redactor is a community mod by Ray Amjad (ray-amjad), from his claude-code-mods collection. A key that reaches the conversation stays there: it is sent to the model on every later turn, saved in the session file, and replayed into forks and subagents. The mod keeps it out. It replaces each secret with a placeholder like [REDACTED-SECRET-5c1e9a7b], and Claude works with the placeholder.
It scans text at every point where it enters the conversation:
- What you type. A key you paste is swapped before the prompt is sent. A toast says how many values were hidden.
- CLAUDE.md and other blocks sent with the first message, and text the engine adds on its own, such as a diff of a changed file or a queued prompt.
- Tool results. A
cat .envshowsPORT=3000and a placeholder for the key. The tool row readstranscript-redactor: hid 1 value(s). - @-mentioned files. A file that holds a key is refused, and Claude is told to use the Read tool instead, whose result is scrubbed.
- Subagent tasks. The prompt is scrubbed before the subagent starts.
The same value always gets the same placeholder within a session, so Claude can still tell two keys apart. When Claude writes a placeholder into a Bash command or a file, the mod puts the real key back first, so curl -H "Authorization: Bearer [REDACTED-SECRET-5c1e9a7b]" really authenticates.
Install
The install block above adds the author's marketplace and installs the plugin from it. There is nothing to call afterwards: it runs on every turn. Mods only load in a folder you have trusted. Restart Claude Code or run /reload-plugins if you installed from a shell into an open session.
$ install transcript-redactor
Requires Claude Code ≥ 2.1.287
Installs from the author's own marketplace: ray-amjad/claude-code-mods
1.One line, inside Claude Code
/plugin install transcript-redactor --marketplace ray-amjad/claude-code-modsPaste into a running session (v2.1.275+). Claude Code asks to add the marketplace first.
2.From your shell
claude plugin marketplace add ray-amjad/claude-code-mods claude plugin install transcript-redactor@claude-code-modsThen run /reload-plugins in any session that is already open.
3.Try it without installing
git clone https://github.com/ray-amjad/claude-code-mods claude --plugin-dir ./claude-code-mods/plugins/transcript-redactorLoads the mod for one session only. Nothing is added to your settings.
How it works
The plugin is one hooks module, hooks/redact.ts, which registers six hooks, and a pure detection file, hooks/detect.ts. A value is hidden when it matches one of about 70 vendor key shapes, a JWT, a private key block, a password in a connection string or after a flag, a long mixed-case token above an entropy floor, or a shorter token right after a name like API_KEY= or "token":. Git SHAs, Stripe object ids and names written in code are kept.
Every hook fails closed. If a scan throws or runs past its budget, the result is withheld rather than passed on. A restored value that contains shell characters is never put into a command. This is from redact.ts:
const SHELL_ACTIVE = /[\s$`"'\\;&|<>()*?[\]{}#~]|[\x00-\x1f\x7f]/
const input = isLocal ? (walk({ ...e }, restoreTracked) as typeof e) : e
if (e.tool === 'Bash' && [...handed].some((v) => SHELL_ACTIVE.test(v))) {
return {
deny: `${brand.name}: a secret in this command holds shell characters, so its real value was not put into Bash, where it could run as code. Write it to a file with the Write tool and have the command read that file instead.`,
}
}
const r = await next(input)After the tool answers, the result, its text and any attached context are scanned, and anything it printed of a restored value is hidden again. A placeholder-shaped string that a tool read back from a file is turned into a quoted [REDACTED-LITERAL-…] placeholder, so a crafted file cannot make the mod write a real key somewhere.
Customize it
Set options with /plugin configure transcript-redactor@claude-code-mods, or under pluginConfigs in your user settings. The main ones:
secrets(default on) andpii(default off, hides emails and public IPs), withhideEmailsandredactPrivateIpsrefining it.restoreInToolInputsandrestoreToolsdecide whether and for which tools a placeholder becomes a real value. The default tools areBash,Write,Edit,MultiEdit,NotebookEdit.notifyturns the tool-row count and the toast on or off.minEntropy(3.6),minLength(24) andcontextMinEntropy(3.0) tune the detector. Raise them to hide less.allow,allowEmails,allowPrefixes,allowUrlHostsanddenyPrefixesmark things to keep or to test anyway. Do not put a host inallowUrlHostsif it carries credentials in the path.
Permissions & safety
We read the manifest, hooks/hooks.json, hooks/redact.ts and all 1,657 lines of hooks/detect.ts before running anything. The plugin has no package.json, no scripts and no binary. It ships PNG screenshots, HTML sources for them and test files, which the plugin does not load; we did not read the HTML or the extra test/*.mts files. What we found:
- No network and no processes. There is no
fetch, socket,child_processor$.process.run. Thehttps://strings indetect.tsare patterns for recognizing Slack and Discord webhooks and similar. - File access.
$.fs.readand$.fs.existsare used only to check an @-mentioned file for secrets (redact.ts:221,:228). The mod writes no files, and nothing under~/.claudeor shell files. The vault is memory only. - Gating hooks.
prompt.submit,tool.call,prompt.mentionandagent.spawncan block or rewrite. That is the purpose of the mod and matches the README. All four have a.catch. If a scan fails, the prompt is dropped, the tool call is denied or its result withheld, or the subagent is not started. A false positive can therefore stop a step, and a workflow agent whose prompt holds a key is refused. - The real key is handed to local tools by design. A placeholder in a
curlcommand insideBashis sent as the real key to whatever host the command names. A placeholder written withWriteorEditlands on disk as the key, and in git if you commit that file. TakeBashout ofrestoreToolsif you would rather it never did. The README states that this is not a defence against a model trying to leak a key. - Secrets, environment, telemetry. It reads no environment variables or credential files and sends nothing anywhere. There is no telemetry.
- Model influence. The only text it injects is its own notices and refusal messages, for example "ask Claude to Read it instead". We found no hidden or zero-width characters and no instructions aimed at the model beyond those.
- No obfuscation. All code is readable TypeScript with no
evalor dynamic import. - License. MIT, with a LICENSE file in the repository root.
claude plugin validate passed with no errors. Its one warning is that the plugin has no icon. claude plugin test ran the author's 37 tests in tests/redact.test.ts on Claude Code 2.1.307, and all passed.
- Reads files
- Can read files and list directories on your machine ($.fs.read / list / stat / exists).
- Intercepts tool calls
- Sees every tool call Claude makes (tool.call / tool.check) and could block or change it.
- Reads your prompts
- Can see what you type and the conversation transcript (prompt.* / session.append / session.messages).
- Changes the UI
- Draws into the Claude Code interface: bands, panes, status text, toasts (ui.render / $.ui.*).
Compatibility & troubleshooting
The mod loaded on Claude Code 2.1.307 on macOS. The author's README says it was tested with 2.1.296. It needs hooks modules, so it does not work on older builds that lack them.
- A command was denied. The message says the secret holds shell characters. Write the value to a file with Write and have the command read the file.
- A result was withheld. It was too large to scan in time, or a secret sat in a part it cannot rewrite. Narrow the call with
head,grepor an offset. - Something harmless is hidden. Add the exact string to
allow, a prefix toallowPrefixes, or raiseminEntropy. - A key is not hidden. A key with no known shape and no name beside it, such as a plain-word password, is missed.
- A placeholder means nothing. The vault is not kept between sessions, so placeholders from an earlier session are not restored.
To check it, ask Claude to run echo "key=sk-ant-abcdefghijklmnopqrstuvwxyz0123456789" with a made-up value, and look for the placeholder and the count on the tool row.
FAQ
- Does the real key ever reach the model?
- Not through the paths the mod hooks. Prompts, CLAUDE.md, attachments, @-mentioned files, subagent tasks and tool results are scanned, and a key is replaced by a placeholder such as [REDACTED-SECRET-5c1e9a7b]. The real value is put back only inside the input of the tools listed in restoreTools, and only for the tool call itself. The README is explicit that this is not a sandbox. Claude can still run a command that transforms or sends the key.
- Is anything written to disk or sent over the network?
- No. The vault that maps placeholders to values is an in-memory map inside the module and dies with the session. The code makes no network requests and starts no processes. It reads a file only to check an @-mentioned file for secrets.
- Which tools get the real value back?
- By default Bash, Write, Edit, MultiEdit and NotebookEdit. Change the list with the restoreTools option. The manifest warns against listing any tool that sends its input to a model or the network, such as Agent, WebFetch or WebSearch. A command that runs git commit, git tag, or gh issue, pr, release and similar never gets real values, so a key cannot end up in a commit message or an issue body.
- Does it hide email addresses and IP addresses too?
- Only if you turn on pii, which is off by default. Then it hides email addresses and public IPv4 and full-form IPv6 addresses. hideEmails set to false keeps emails readable, and redactPrivateIps adds private ranges. Addresses such as noreply@, @example.com and anything in allowEmails are left alone.
- Can I run it together with another secret redactor?
- The README says to run this mod or its sibling secret-box, not both, and the same advice applies to any other redactor. Two mods that rewrite the same text each keep their own vault, and one would restore placeholders that the other minted.
# Related mods
FeaturedSecret Redactor
Swaps API keys, emails and public IPs for placeholders before Claude sees them, and restores them when a tool runs.
- toast
- Intercepts tool calls
- Reads your prompts
- Changes the UI
tested with v2.1.291
PII Guard
Replaces Taiwanese personal data with placeholders before Claude sees it and restores real values when Claude writes.
- none
- Reads files
- Runs commands
- Network
- Intercepts tool calls
- Reads your prompts
tested with v2.1.291
FeaturedBlock Dangerous Commands
Refuses rm -rf /, force-push to main, DROP TABLE, curl | sh and other destructive Bash commands before they run.
- toast
- Intercepts tool calls
- Changes the UI
tested with v2.1.310
More in Safety guards, Tools you add to Claude.