SLOPSHOPPER

redacton-ui-qualification

Synthetic local UI tool activity probe

newcommand
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · redacton-ui-qualification
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /ui-tool-probe ⎿ redacton-ui-qualification: UI_TOOL_NOT_COMPLETED ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

Redacton

MIT License TypeScript Claude Code Powered by Redact Secret

Keep recognized credentials out of supported Claude Code model inputs. Redacton scans prompt text/context, Read text, and Bash stdout/stderr, replacing detected credentials with placeholders. Recognized private keys block the entire event.

Redacton targets macOS, Linux and Windows CLI installations with one shared Mod/helper implementation. The published verified release remains macOS ARM64, Claude Code 2.1.294, Node 22.16.0. Portable packages, Unix/PowerShell candidate installers and CI are development paths until each platform's actual host is qualified. See the target and verified matrix.

Powered by Redact Secret, a deterministic Rust detection engine with native and WebAssembly runtimes. Scanning runs locally, without sending content to a detection service. Explore Redact Secret for local redaction in your own apps, and star the project to support it.

Install in two minutes

This command installs the existing verified macOS Apple Silicon release, not a universal cross-platform package.

Have Claude Code and Node.js 22 installed on macOS Apple Silicon. The verified combination is Claude Code 2.1.294 and Node 22.16.0; other platforms, host versions and Desktop have not been qualified. Required follow-on support targets macOS x64, Linux x64/ARM64 and Windows x64/WSL; those targets are not supported by this installer.

curl -fsSL https://raw.githubusercontent.com/milocosmopolitan/redacton/main/scripts/install.sh | bash
claude --plugin-dir "$HOME/.local/share/redacton/current"

The installer downloads the published package, verifies its pinned checksum, and installs it without npm or a build step. You can inspect the installer or download packages from Releases.

The --plugin-dir option loads Redacton for that Claude Code launch. Use the same launch command for future sessions.

Linux, Intel Mac, native Windows and WSL users should follow the candidate installation and qualification guidance. Native Windows and WSL are separate environments; Desktop is a separate host surface. A helper/installer success does not establish protection of model inputs.

Use it

After launch, run /redacton and confirm Protect ready before your first task.

New, resumed and branched CLI sessions start with protection requested ON. Readiness is shown separately as loading, ready or unavailable.

CommandEffect
/redactonRequest protection for subsequent supported operations.
/redactoffBypass scans for subsequent operations in this session.
/redact:statusShow cached readiness, coverage, rules and recent outcomes.
/redact:config, /redact:add-rule, /redact:remove-ruleManage custom formats through local forms.

Commands take no arguments. Never paste secrets, patterns or test text into slash-command arguments; the host can store them before local rejection. Running operations keep the policy they started with. OFF displays a prompt-area warning: ⚠ Redacton OFF — credential protection disabled.

Custom rules use guided token formats or assignment names. Validate, inspect synthetic sample outcomes, then explicitly Apply session; personal/project saving and portable import/export are separate actions. Confirm the form has keyboard focus before typing, and close it before ordinary chat. Never enter actual credential values as rule definitions. See configuration and scope.

Know the boundaries

Protection depends on the functioning host and outer guard. Unsupported selected results and scanner failures withhold content under those guard conditions; a host that bypasses all guards can expose it.

Original prompts and tool arguments can remain in host storage. Encoded credentials can be missed, and zero findings does not mean safe content. MCP, other tools, tool arguments, binary/image/audio content, PII and existing history are outside coverage. Withholding output does not undo a tool's effects.

See compatibility and evidence and the threat model for exact limits. For vulnerabilities, use private security reporting; public issues are not confidential.

Contributing · Security policy · Code of conduct · Dependency notices · MIT license

Source 1 files
hooks/register.js 20 lines
1export function register(on) {
2  on('session.start', async ($, e, next) => {
3    await $.command.register({ name: 'ui-tool-probe', description: 'Synthetic local Bash UI qualification' })
4    await $.command.register({name:'ui-custom-probe',description:'Synthetic local configured credential qualification'})
5    return next(e)
6  })
7  on('command.run', {command:'ui-custom-probe'}, async ($)=>{
8    const answer=await $.tool.call({tool:'Bash',command:"printf x >> ui-execution-counter; printf '%s\\n' 'syntheticcred_ABCDEF0123456789'; printf '%s\\n' 'syntheticcred_ABCDEF0123456789' >&2",description:'Synthetic configured credential qualification'});
9    const result=answer.result;
10    const denied=['REDACTON_UNAVAILABLE','REDACTON_UNSUPPORTED_SHAPE','REDACTON_WITHHELD','REDACTON_TOOL_DENIED','REDACTON_INPUT_LIMIT'].includes(answer.deny)?answer.deny:'OTHER';
11    const combined=String(result?.stdout??'')+String(result?.stderr??'');
12    return {text:!combined.includes('syntheticcred_ABCDEF0123456789') && combined.includes('<SECRET_1>')?'UI_CUSTOM_SANITIZED':combined.includes('syntheticcred_ABCDEF0123456789')?'UI_CUSTOM_RAW_OFF':`UI_CUSTOM_WITHHELD_${denied}`}
13
14  }).catch(()=>({text:'UI_CUSTOM_WITHHELD'}))
15  on('command.run', { command: 'ui-tool-probe' }, async ($) => {
16    const answer = await $.tool.call({ tool: 'Bash', command: 'printf UI_SYNTHETIC_ACTIVITY', description: 'Synthetic UI qualification' })
17    return { text: answer.result?.stdout === 'UI_SYNTHETIC_ACTIVITY' ? 'UI_TOOL_COMPLETED' : 'UI_TOOL_NOT_COMPLETED' }
18  }).catch(() => ({ text: 'UI_TOOL_NOT_COMPLETED' }))
19}
20