{"slug": "show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env", "title": "Show HN: A 60-line PreToolUse hook that stops Claude Code from editing your .env", "summary": "A developer released a 60-line PreToolUse hook that prevents Claude Code from editing protected files like .env, addressing the failure of prompt-based rules in CLAUDE.md to stop the AI from modifying sensitive files. The guard, part of the claude-code-survival-kr repository, runs before tool calls and blocks edits to paths listed in a protected.txt file, returning the reason on stderr so the model stops instead of retrying.", "body_md": "`CLAUDE.md`\n\nis advice. The model reads it, the conversation gets long, the rule\nloses priority, and it edits the file anyway.\n\nThat is not a prompting problem. No wording fixes it.\n\n**This is not advice. It runs before the tool call and refuses it.**\n\n```\nBlocked by guard.py: .env\nIt matches the pattern '.env' listed in .claude/protected.txt.\n```\n\nThe model never gets to write. It gets told why, and moves on.\n\n```\nmkdir -p .claude\ncurl -o .claude/guard.py        https://raw.githubusercontent.com/avenna01-ceo/claude-code-survival-kr/main/guard/guard.py\ncurl -o .claude/protected.txt   https://raw.githubusercontent.com/avenna01-ceo/claude-code-survival-kr/main/guard/protected.txt\ncurl -o .claude/settings.json   https://raw.githubusercontent.com/avenna01-ceo/claude-code-survival-kr/main/guard/settings.json\n```\n\nAlready have a `.claude/settings.json`\n\n? Merge this in instead of overwriting:\n\n```\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Edit|Write|MultiEdit|NotebookEdit\",\n        \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 .claude/guard.py\" }]\n      }\n    ]\n  }\n}\n```\n\nOn Windows use `python`\n\ninstead of `python3`\n\n.\n\nRestart Claude Code. That's it — no dependencies, Python 3.8+.\n\nEdit `.claude/protected.txt`\n\n. One pattern per line.\n\n```\n.env\n.env.*\n*.pem\n*.key\ncredentials.json\n\nmigrations/**\nlegacy/**\n\n.claude/guard.py\n.claude/protected.txt\n.claude/settings.json\n```\n\nA bare filename matches **anywhere in the tree**, because that's what you mean\nwhen you type it. `.env`\n\nblocks `./.env`\n\nand `api/.env`\n\nboth. `dir/**`\n\nblocks\neverything under that directory.\n\nKeep the last three lines. They are what stops the model from disabling its own guard when it gets stuck.\n\n```\necho '{\"tool_name\":\"Edit\",\"tool_input\":{\"file_path\":\".env\"},\"cwd\":\"'\"$PWD\"'\"}' | python3 .claude/guard.py; echo \"exit=$?\"\n```\n\n`exit=2`\n\nmeans it's live. `exit=0`\n\non a protected path means the pattern didn't match.\n\n**Does**\n\n- Blocks\n`Edit`\n\n,`Write`\n\n,`MultiEdit`\n\n,`NotebookEdit`\n\non paths you list - Reads every path in a\n`MultiEdit`\n\nbatch, not just the first - Returns the reason on stderr, so the model stops instead of retrying\n- Fails\n**open**— if the hook itself errors, your work continues. A guard that breaks everything when it breaks is worse than no guard.\n\n**Doesn't**\n\n- Doesn't block\n`Bash`\n\n.`rm -rf`\n\nstill goes through. Gate that separately, or add a`Bash`\n\nmatcher and inspect the command string. - Doesn't protect against a user who edits\n`protected.txt`\n\nthemselves. It's a guardrail, not a permission system.\n\n| Where it lives | When it loses | |\n|---|---|---|\n`CLAUDE.md` |\nin the prompt | context gets long, priority drops |\nhook |\nin your machine | never — it isn't the model's decision |\n\nRules are advisory. Hooks are enforcement. Use both: `CLAUDE.md`\n\nfor *why*,\n`guard.py`\n\nfor *can't*.\n\nPart of [claude-code-survival-kr](https://github.com/avenna01-ceo/claude-code-survival-kr) —\nrules and prompts that stop AI from breaking working code. MIT.", "url": "https://wpnews.pro/news/show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env", "canonical_source": "https://github.com/avenna01-ceo/claude-code-survival-kr/tree/main/guard", "published_at": "2026-07-27 00:52:32+00:00", "updated_at": "2026-07-27 01:22:22.355947+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-safety"], "entities": ["Claude Code", "claude-code-survival-kr", "avenna01-ceo"], "alternates": {"html": "https://wpnews.pro/news/show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env", "markdown": "https://wpnews.pro/news/show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env.md", "text": "https://wpnews.pro/news/show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env.txt", "jsonld": "https://wpnews.pro/news/show-hn-a-60-line-pretooluse-hook-that-stops-claude-code-from-editing-your-env.jsonld"}}