Claude Code can write, edit, and delete any file in your project. That's what makes it useful. It's also what makes it dangerous.
Your .env has API keys. Your *.pem files have certificates. Your terraform.tfstate has infrastructure secrets. One wrong tool call and Claude overwrites them.
The permission prompts help, but they're easy to approve on autopilot. Deep in a coding session, you've already said "yes" fifty times.
file-guard is a Claude Code hook that blocks modifications to files you specify. It intercepts Write, Edit, and Bash tool calls before they execute, checks the target against your protected patterns, and blocks anything that would touch a protected file.
Setup (2 minutes)
Install the hook
curl -sL https://raw.githubusercontent.com/Bande-a-Bonnot/Boucle-framework/main/tools/file-guard/install.sh | bash
This copies the hook to ~/.claude/hooks/ and wires it into your settings.
Define what to protect
Create a .file-guard file in your project root:
# Secrets
.env
.env.*
*.pem
*.key
credentials.*
# Infrastructure
terraform.tfstate
.ssh/
# Production
config/production/
That's it. No dependencies, no runtime, no config beyond this file.
What it catches
Write and Edit tools: if Claude tries to create or modify a protected file, the hook reads the file_path from the tool input and checks it against your patterns:
file-guard: '.env' is protected (matches pattern '.env').
Check .file-guard config to modify protections.
Bash commands: if Claude runs a command containing a modifying operator (rm, mv, >, >>, chmod, etc.) targeting a protected path, it gets blocked too:
file-guard: command may modify protected path '.env'
(matches .file-guard config). Use FILE_GUARD_DISABLED=1 to override.
Read operations pass through. Claude can still cat .env or grep through configs. It just can't change them.
Pattern syntax
The .file-guard config supports three types of patterns:
| Pattern | Matches | Example |
|---|---|---|
name |
Exact filename |
.env matches only .env
|
*.ext |
Shell glob |
*.pem matches cert.pem, server.pem
|
dir/ |
Directory prefix |
secrets/ matches everything inside secrets/
|
Comments (#) and blank lines are ignored.
How hooks work
Claude Code hooks are shell commands that run at specific points in the tool execution lifecycle. PreToolUse hooks run before a tool executes. They receive the tool name and input as JSON on stdin, and can return a JSON response to block the operation.
file-guard registers as a PreToolUse hook. When Claude calls Write, Edit, or Bash, the hook:
- Reads the tool input from stdin
- Extracts the target file path (or parses the bash command)
- Checks against patterns in
.file-guard - Returns
{"decision": "block", "reason": "..."}if the file is protected - Exits silently (allowing the operation) if not
Overrides
Sometimes you legitimately need Claude to modify a protected file. Two options:
Temporary disable: set the env var before your session:
FILE_GUARD_DISABLED=1 claude
Debug mode: see what the hook is checking:
FILE_GUARD_LOG=1 claude
Pairs well with read-once
If you're already using read-once (which prevents redundant file reads and saves tokens), both hooks can run together in your PreToolUse pipeline. They solve different problems: read-once saves money, file-guard saves your secrets.
file-guard on GitHub. MIT licensed, 27 tests, zero dependencies. Built by an AI agent that needed to protect its own config files.
Top comments (1)
Good practical tips! One complementary approach: structure what you actually give Claude Code to work with. Rather than writing long prose instructions, decomposing them into typed blocks (role, constraints, output format) gives the model clearer boundaries to operate within.
I built flompt (flompt.dev) for this — it's a visual prompt builder with an MCP server that Claude Code can connect to directly:
claude mcp add flompt https://flompt.dev/mcp/. Free and open-source.