Joe Bruechner
Projects

guard

Reads stdin, redacts API keys and high-entropy strings inline, writes the cleaned content to stdout. Reports go to stderr so the pipe stays clean. Installable as a Claude Code skill for one-shot clipboard, file, or pre-commit scans.

v0.1May 2026
01

The Problem

Hard-coded secrets keep landing in production. The pattern is familiar — a key gets dropped inline during a debug session, the file gets committed, the commit gets pushed, and a few weeks later it's quoted in a postmortem. Some of the largest platforms in the industry have shipped this exact bug recently, and the failure mode hasn't gotten any rarer as codebases get bigger and pipelines get faster. The cleanup is always more expensive than the catch would have been.

There's also a newer wrinkle: LLMs are getting aggressively sensitive about anything that looks like a credential. Claude Code recently scanned a `package.json` of mine, decided a registry token-shaped string was a real secret, and killed the session for a privacy-policy violation. The string wasn't a secret — but the model couldn't tell, and there was no in-band way to redact and continue. The friction is going to keep growing in both directions: secrets you didn't notice slipping out, and innocuous strings being flagged as secrets and blocking work.

Existing scanners are built for CI — heavy, networked, repo-aware, slow to spin up. None of them fit the gesture I actually wanted: pipe content in, get cleaned content out, on the way to my clipboard, an LLM, or a commit. So I built one that runs in single-digit milliseconds and slots into the moments where this actually goes wrong.

02

The Tool

guard is a single-binary CLI written in Zig. It reads stdin, redacts secrets inline with typed placeholders like `[REDACTED:anthropic-api-key:1]`, writes the cleaned content to stdout, and writes the report to stderr. The pipe is never contaminated by the report — `cat src/api.ts | guard | pbcopy` puts only the redacted content on the clipboard, regardless of what flags you pass.

Detection covers 19 provider patterns — Anthropic, OpenAI, GitHub, AWS, Stripe, Slack, Linear, GCP OAuth, JWT, and others — plus a Shannon-entropy fallback for unknown providers. Each provider pattern validates trailing characters against a charset and length range to keep false positives low. The entropy threshold is tunable via `--entropy-threshold`.

terminal-usage.sh
# Sanitize before pasting into an LLM
cat src/api/client.ts | guard | pbcopy

# With a human-readable report on stderr
cat src/api/client.ts | guard --summary | pbcopy

# Sanitize a staged diff before committing
git diff --staged | guard | pbcopy

# Machine-readable report (for tooling, CI, agent integration)
cat secrets.env | guard --json

# Drop known-safe values (fixtures, examples)
echo 'AKIAIOSFODNN7EXAMPLE' | guard --allow EXAMPLE

# Handy aliases
alias llmcopy="guard --summary | pbcopy"
alias diffcopy="git diff --staged | guard --summary | pbcopy"
# Sanitize before pasting into an LLM
cat src/api/client.ts | guard | pbcopy

# With a human-readable report on stderr
cat src/api/client.ts | guard --summary | pbcopy

# Sanitize a staged diff before committing
git diff --staged | guard | pbcopy

# Machine-readable report (for tooling, CI, agent integration)
cat secrets.env | guard --json

# Drop known-safe values (fixtures, examples)
echo 'AKIAIOSFODNN7EXAMPLE' | guard --allow EXAMPLE

# Handy aliases
alias llmcopy="guard --summary | pbcopy"
alias diffcopy="git diff --staged | guard --summary | pbcopy"
stdout always carries only the redacted content. stderr is for reports. The pipe is never contaminated by either flag combination.
  • Stable placeholders — same secret in one input always reuses the same index, so an LLM can tell whether two references point to the same key
  • No cross-run linkability — there is no content hash; running guard twice on the same input never produces a value an attacker can correlate
  • Escape hatches — `# noscan` / `// noscan` per-line, or `--allow <substring>` to let known-safe values through
  • Exit codes — 0 clean, 1 redacted, 2 invocation error — usable as a pre-commit gate or CI check
  • Cross-platform binaries — aarch64-macos, x86_64-macos, x86_64-linux, aarch64-linux. SHA-256 checksums published per release
03

Claude Code Skill

guard ships as an installable Claude Code skill. Drop the SKILL.md into `~/.claude/skills/guard/` and Claude Code can run guard for you on the clipboard, on a file, or on a staged diff — all routed through the right invocation depending on what you pass.

The skill turns the gesture into a single keystroke. `/guard` redacts the clipboard in place. `/guard <path>` summarizes what would be redacted in a file. `/guard diff` runs a pre-commit secret scan on `git diff --staged` — handy as the last check before a commit. The skill explicitly tells Claude to never echo original secret values back in chat, only the placeholders, so the agent can't accidentally leak what guard just hid.

skill-install.sh
# Install guard
curl -fsSL https://raw.githubusercontent.com/brueshi/guard/main/install.sh | sh

# Install the Claude Code skill
mkdir -p ~/.claude/skills/guard && \
  curl -fsSL https://raw.githubusercontent.com/brueshi/guard/main/skills/guard/SKILL.md \
  -o ~/.claude/skills/guard/SKILL.md

# Then in Claude Code:
#   /guard          → pbpaste | guard --summary | pbcopy
#   /guard <path>   → cat <path> | guard --summary
#   /guard diff     → git diff --staged | guard --summary  (pre-commit scan)
#   /guard <text>   → scan literal text
# Install guard
curl -fsSL https://raw.githubusercontent.com/brueshi/guard/main/install.sh | sh

# Install the Claude Code skill
mkdir -p ~/.claude/skills/guard && \
  curl -fsSL https://raw.githubusercontent.com/brueshi/guard/main/skills/guard/SKILL.md \
  -o ~/.claude/skills/guard/SKILL.md

# Then in Claude Code:
#   /guard          → pbpaste | guard --summary | pbcopy
#   /guard <path>   → cat <path> | guard --summary
#   /guard diff     → git diff --staged | guard --summary  (pre-commit scan)
#   /guard <text>   → scan literal text
guard is installable as a Claude Code skill — turning the gesture into a one-keystroke /guard.
04

Why Zig

The detection loop is unrolled at build time. Every provider pattern is a comptime struct, and the matcher iterates them through `inline for` — the result is a flat match path with no dynamic dispatch and no per-pattern function call overhead. That kind of optimization is awkward in Go or Rust and trivial in Zig.

There is no regex engine. Prefix matching plus charset and length validation plus optional structural constraints (e.g. JWT requires three base64url segments separated by dots) covers all 19 supported patterns without a regex dependency. The whole binary stays under a megabyte and starts in single-digit milliseconds — fast enough that piping into it never feels like a step.

Cross-compilation is also free in Zig. `zig build -Dtarget=aarch64-linux` produces a working Linux binary from macOS without a separate toolchain. The release script builds all four platforms in one pass.

Built with
Zig