A fact-forcing hook gate for Claude Code. Makes the AI pause and investigate before editing.
Project description
GateGuard
A fact-forcing hook gate for Claude Code.
GateGuard makes Claude Code pause and investigate before it edits your files. When Claude tries to modify, create, or run something, the gate blocks the first attempt and forces Claude to present concrete facts — who imports this file, what the data actually looks like, what the user's instruction was — before it is allowed to proceed.
Self-evaluation ("are you sure?") doesn't change LLM behavior. Forced investigation does. GateGuard is the smallest thing that reliably moves that needle.
Evidence: A/B test results
We tested two identical Claude Code agents on the same task — creating a new analytics module that integrates with an existing codebase.
| Metric | With GateGuard | Without GateGuard |
|---|---|---|
| Quality score | 8.0 / 10 | 6.5 / 10 |
| Tool calls | 11 | 21 |
| Time | 114s | 142s |
| Internal subsystem integration | Yes | Missed |
| Zero-filled daily data | Yes | Missing |
| Extra metrics (avg/day) | Yes | Missing |
The quality gap comes from investigation depth. The gated agent was forced to read existing code patterns before writing — so it discovered subsystem integration points that the ungated agent simply guessed at (incorrectly).
These are the errors tests don't catch: the code runs, but the design is shallow. Over a 10-file project, this 1.5-point-per-file gap compounds into significant rework.
Install
pip install gateguard-ai
Quick start
From the project directory you want to protect:
gateguard init
This does three things:
- Writes
.gateguard.ymlinto the current directory. - Registers a
PreToolUsehook in~/.claude/settings.jsonthat runsgateguard-hookon everyEdit,Write, andBashcall. - Registers a
PostToolUsehook that tracks which files have beenRead(needed for the Read-before-Edit gate).
Restart Claude Code and the gate is active.
What the gates do
| Gate | Trigger | What Claude must do |
|---|---|---|
| Read-before-Edit | Edit on a file not yet Read this session |
Read the file first |
| Fact-force Edit | First Edit per file |
List importers, affected public API, verify data schemas from real records, quote the user's instruction |
| Fact-force Write | First Write per file |
Name call sites, confirm no duplicate exists, verify data schemas, quote the instruction |
| Fact-force destructive Bash | rm -rf, git reset --hard, drop table, etc. |
List what will be destroyed, give a rollback, quote the instruction |
| Fact-force routine Bash | First Bash per session |
Quote the user's current instruction |
Each gate fires once per target per session. After the facts are presented, the next attempt passes through.
Why "verify data schemas"?
In our A/B test, both agents (gated and ungated) wrote code that assumed
ISO-8601 dates and bare JSON arrays. The real data used %Y/%m/%d %H:%M dates
and {"schema_version": "1.0", "items": [...]} wrappers. Both agents got this
wrong — because neither actually looked at the data.
v0.2.0 adds a new gate item: "If this file reads/writes data files, cat one real record and show the actual field names, structure, and date format." This forces the LLM to verify assumptions against reality before writing code.
Configuration
gateguard init writes a .gateguard.yml you can edit:
enabled: true
gates:
read_before_edit: true
fact_force_edit: true
fact_force_write: true
fact_force_bash_destructive: true
fact_force_bash_routine: true
destructive_bash_extra:
- "supabase db reset"
- "prisma migrate reset"
messages:
edit: |
Before editing {file_path}, present:
1. ...
ignore_paths:
- ".venv/**"
- "node_modules/**"
- ".git/**"
CLI
gateguard init [path] [--force] [--skip-hook]
gateguard logs [--tail N]
gateguard reset
gateguard --version
init— write.gateguard.ymland register both hookslogs— print recent gate events from~/.gateguard/gate_log.jsonlreset— clear the in-session state (~/.gateguard/.session_state.json)
How it works
The core insight: asking an LLM to evaluate itself ("did you violate any
policies?") doesn't change its behavior. It always says no. But asking it to
gather facts — "list every file that imports this module" — forces it to use
Grep and Read. The act of investigation creates awareness that the
self-evaluation never did.
Every competitor in the AI guardrails space stops at deny. GateGuard does deny + force investigation + demand evidence. The model can't proceed until it has demonstrated understanding.
GateGuard is a Claude Code PreToolUse hook that:
- Denies the first attempt at Edit/Write/Bash
- Tells the model exactly which facts to gather (importers, public API, data schemas, user instruction)
- Allows the retry after facts are presented
The second attempt succeeds — but now the model has context it didn't have before, producing measurably better code.
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gateguard_ai-0.2.2.tar.gz.
File metadata
- Download URL: gateguard_ai-0.2.2.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd6d54b194f07ea25b8535e6c2beafae0143aa3c7e33935ebd16a759be678210
|
|
| MD5 |
e8907952715b1b483335c080aefa8791
|
|
| BLAKE2b-256 |
744a1367d9ae6f14ed9029128f3df2166698ca4c79f1a4a50e1276d1fd3c4fb3
|
File details
Details for the file gateguard_ai-0.2.2-py3-none-any.whl.
File metadata
- Download URL: gateguard_ai-0.2.2-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26561fbad1b961297a072e6586a99e11adb4dfa4bdd46caa364c5a1205b40405
|
|
| MD5 |
29b6b4be221dac47147fb282f72630ee
|
|
| BLAKE2b-256 |
9e45328512ec153fb91de90adc77b1f90e7ceb23ce2ae6c47fe6b04cca4ed2aa
|