I let AI coding agents do a lot of the chores on my machines: moving files around, cleaning up folders, writing the little scripts nobody wants to write. They're good at it. But they all share one reflex I don't want anywhere near private files: when you ask them to check something, they hash it.
"Copy these clips to the backup drive and make sure nothing got corrupted" turns into sha256sum on both sides. "Find the duplicates" turns into fdupes. "Keep these in sync" turns into rsync. A quick indexing script grows a hashlib cache key. For source code that's exactly what you want. For private media it isn't, so I built a fence around it and open-sourced it: No-Hash Zone.
Why a hash counts as a leak
A hash feels harmless. It's a short string of hex, you can't turn it back into the file, so who cares? Here's who:
- It identifies the exact file. Anyone holding the same file, or a list of hashes, can tell that you have it. That's how known files get matched across systems: not by looking at them, by comparing fingerprints.
- It links copies. The same value on two drives, two machines or two cloud accounts ties them together.
- It outlives the task. With an agent, the value lands in the terminal output, the session transcript and maybe a log or a memory file, and it goes to the model provider as part of the conversation. You never uploaded the file, and something derived from it still left the folder.
- Perceptual hashes go further. pHash, dHash and their relatives still match a photo or a video frame after it has been resized, re-encoded or cropped. That's the whole point of them.
If you work with unreleased footage, client shoots, interviews, legal or medical scans, or anything under an NDA, that's a problem you never signed up for.
What No-Hash Zone is
Two layers for Claude Code, and each one covers the other's blind spot:
- A policy, a block for your
CLAUDE.md. It tells the agent which folders, drives and shares are a no-hashing zone; what counts as hashing (every algorithm, every checksum, every fingerprint, under any name, done directly or handed off to another tool); what's still fine (names, sizes, dates); and what to do when a task seems to need a hash: stop, say why, offer a metadata-only way, never quietly fall back. - A guard, a small
PreToolUsehook that runs before every shell command the agent is about to run. If the command touches a protected location and uses a hashing operation, Claude Code refuses it and the agent reads why. Everything else passes untouched.
The policy handles judgement: the tool nobody thought to list, the subagent it might hand the job to. The guard handles the moment a rule gets lost three hours into a long session.
How the guard decides
Claude Code hands the pending command to the hook as JSON. The hook lower-cases it, turns backslashes into forward slashes, and asks two questions: does this command mention a protected location, or run from inside one? And does it use something that derives a value from file contents? Two yeses and it answers with a deny:
Claude wants to run: rsync -a /Volumes/Private/shoot-0412/ /Volumes/Backup/shoot-0412/
The guard answers: deny
"No-hash zone: this command would hash, checksum or fingerprint
files in a protected location (rsync and content-based dedup
included). Work from metadata instead (names, sizes, dates),
or ask the owner."
Claude Code doesn't run the command, and the agent reads the reason and changes course. Each protected location is matched in every spelling a shell might use: either slash direction, any letter case, ~ and $HOME, the Git Bash and WSL forms of a Windows drive, and smb:// for a network share. It also fails closed: if the guard can't read its input or its config, or can't start at all, the command doesn't run.
It knows the obvious tools (md5, the sha*sum family, Get-FileHash, certutil -hashfile, hashlib, crypto.createHash), the duplicate finders, and the sync and backup tools that checksum or chunk content (rsync, rclone, restic, borg, git add). It also knows the ones media people actually trip over: ffmpeg's md5 and framemd5 outputs, ImageMagick's %# image signature, ExifTool's image-data hash and the perceptual-hash libraries.
What changes day to day
Not much, and that's the point. The agent still copies, moves, lists, renames and organizes everything. It just checks a copy by names, counts and sizes, flags likely duplicates by name and size, and builds its indexes from metadata. When a job genuinely needs a content comparison, it stops and asks instead of doing it quietly. Hashing a download in ~/Downloads still works fine; only the places you list are fenced off.
Install
You need Claude Code and Node.js 18 or newer. Clone it and tell it what to protect:
git clone https://github.com/AcidAlchamy/no-hash-zone.git
cd no-hash-zone
node install.mjs --path "/Volumes/Private" --path "$HOME/Clients"
On Windows it's the same with Windows paths: --path "D:\Private" --path "\\nas\clients". The installer copies the guard, writes your list, adds one entry to settings.json and puts the policy at the top of your CLAUDE.md, backing both files up first. --dry-run shows what it would do, --uninstall takes it back out. Then start a new session.
Honest limits
- It reads the command line, not what a command does.
python index.pygets through even if the script hashes everything. The policy still forbids it; the guard just can't see inside the script. - It knows the tools it lists. Add your own in the config.
- It guards the agent's shell commands, not your own terminal, and not other apps like backup clients or photo libraries.
- It errs on the side of the files:
grep checksum /mnt/private/notes.txtgets refused too.
It's a seatbelt, not a vault. For hard isolation, use the operating system: file permissions, a separate account, an encrypted volume that stays locked.
Get it
No-Hash Zone is free and open source under Apache-2.0: github.com/AcidAlchamy/no-hash-zone. It's about 150 lines of dependency-free JavaScript plus a policy you can read in five minutes, and its 39-case test suite passes on macOS, Linux and Windows. If your agent works anywhere near files that aren't yours to fingerprint, put a fence around them.