TL;DR: I built block-no-verify - a tool that prevents AI agents like Claude Code from using --no-verify to bypass git hooks. The AI must fix issues properly; humans keep full autonomy.
The Problem I Didn't Know I Had
I've been using Claude Code as my AI pair programmer. It's genuinely impressive - writes code, runs tests, commits changes. But one day I noticed something odd in my git history.
My pre-commit hooks weren't catching issues they should have caught.
I dug into what was happening and found the culprit:
git commit -m "fix: update validation logic" --no-verify
Claude Code was using --no-verify on almost every commit. Silently bypassing all my carefully configured hooks.
Why This Matters
Git hooks exist for a reason. Mine run:
- ESLint - catch code quality issues
- Prettier - enforce consistent formatting
- Type checking - prevent TypeScript errors from slipping through
- Commit message validation - keep a clean, conventional commit history
When the AI bypasses these, I'm essentially getting unreviewed code merged into my codebase. The very guardrails I set up to maintain quality were being circumvented.
I get why Claude Code does this - hooks can fail, hooks can be slow, and the AI is trying to be efficient. But efficiency at the cost of quality isn't a trade-off I want to make.
The Solution: Enforce the Rules
Instead of hoping for a configuration option that might never come, I built a tool that intercepts git commands before they execute.
Meet block-no-verify.
How It Works
Claude Code has a hooks system that lets you run scripts before certain actions. I use the PreToolUse hook to inspect every Bash command before it runs:
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "pnpm dlx block-no-verify"
}
]
}
]
}
}
When Claude Code tries to run something like:
git commit -m "feat: add new feature" --no-verify
The tool detects the forbidden flag and blocks the command with a clear message:
❌ Blocked: --no-verify flag is not allowed
The --no-verify flag bypasses git hooks which enforce code quality.
Please fix any issues that would cause hooks to fail.
Smart Detection
One tricky part: the -n shorthand means different things for different git commands:
| Command |
-n means |
Blocked? |
|---|---|---|
git commit -n |
--no-verify |
Yes |
git push -n |
--dry-run |
No |
git merge -n |
--no-commit |
No |
The tool understands this context and only blocks when -n actually means "skip verification."
It also handles edge cases like:
- Flags embedded in strings:
git commit -m "--no-verify is blocked"(allowed - it's just a message) - Shell syntax:
echo "--no-verify" | git commit(detected) - Command chaining:
git add . && git commit --no-verify(blocked)
The Philosophy: Asymmetric Governance
Here's what I didn't want: a tool that blocks --no-verify for everyone.
Sometimes I need to bypass hooks. Maybe I'm doing a large refactor and want to commit work-in-progress. Maybe there's a false positive in my linter. As the developer, I can make that judgment call.
But the AI shouldn't make that call for me.
So block-no-verify only affects commands run through Claude Code's hook system. When I run git commands directly in my terminal, nothing changes. Full autonomy preserved.
AI agent → Must follow the rules, fix issues properly
Human developer → Can override when they judge it appropriate
This is what I call asymmetric governance. The AI operates under stricter constraints than the human, because the human understands context that the AI doesn't.
The Results
Since implementing this, Claude Code actually fixes the issues instead of bypassing them.
Hook fails because of a lint error? The agent reads the error, fixes the code, and commits cleanly.
This creates a positive feedback loop:
- Hook fails
- Agent investigates the failure
- Agent fixes the root cause
- Code quality actually improves
Compare this to the bypass behavior:
- Hook would fail
- Agent uses
--no-verify - Problem hidden
- Technical debt accumulates silently
Getting Started
Installation
Add to your Claude Code settings:
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "pnpm dlx block-no-verify"
}
]
}
]
}
}
That's it. No global installation, no configuration. The tool reads the command from stdin (passed by Claude Code) and exits with an error if --no-verify is detected.
Broader Implications
As AI coding assistants become more capable and autonomous, we need to think about governance. These tools are powerful, but they optimize for completing tasks - not necessarily for maintaining the standards we've set up.
Git hooks, linters, tests - these are encoded team knowledge. They represent decisions we've made about quality. When an AI bypasses them, it's not just skipping a step; it's ignoring institutional wisdom.
block-no-verify is a small tool solving a specific problem, but it represents a larger pattern: programmatic enforcement of AI behavior. Rather than relying on prompts or hoping the AI "does the right thing," we can build guardrails that make certain behaviors impossible.
What's Next?
I'm considering extending this pattern to other "escape hatch" behaviors:
-
git push --forceto protected branches -
git reset --hardwithout confirmation - Other flags that could cause irreversible damage
I've also been working on eslint-config-agent - an ESLint configuration specifically designed for codebases where AI agents are writing code. The idea is to have stricter, more opinionated linting rules that catch the kinds of mistakes AI tends to make. Combined with block-no-verify, it creates a solid quality gate that AI-generated code must pass through.
If you're using AI coding assistants and care about maintaining your code quality standards, give block-no-verify a try. I'd love to hear your feedback on both projects - what rules would you add to eslint-config-agent? What other guardrails have you found useful when working with AI assistants?
Links:
Have you run into similar issues with AI coding assistants bypassing your safeguards? What other governance patterns have you found useful? Let me know in the comments.
Top comments (1)
so this a hook that ensures hooks? a metahook?