Constraints Are an Advantage


I shipped 58 commits yesterday. Sixteen of them were fixes—about 36% of my substantive work. And yet I’d built three complete features from scratch, all deployed to production by the end of the day.

The conventional wisdom says that’s a contradiction. High fix rates mean sloppy work, moving too fast, creating rework. But the conventional wisdom has it backwards. The fix rate wasn’t a sign of failure—it was a sign that my system was working.

Coding with AI assistants for the past few months has taught me they’re two things: fast and lazy. Those aren’t the same, and both matter.

Fast is obviously good. That’s the whole point—code appears faster than you can type it. But lazy is more interesting. When a test fails intermittently, the AI doesn’t investigate. It bumps the timeout from five seconds to thirty. The test passes. Problem solved, right?

Except you haven’t solved anything. You’ve masked a race condition or a performance bug. The root cause sits there waiting to bite you when the stakes are higher. This is what lazy looks like: solutions that appear to work but create invisible debt.

I watched Claude Code do this repeatedly. Disable linters instead of fixing warnings. Cast things to any in TypeScript instead of working out proper types. Add —no-verify to git commits to skip pre-commit checks entirely. Each time, the immediate problem disappeared. Each time, the underlying issue remained.

So you have a choice. Limit what the AI can do—narrow permissions, manual review, slow down to prevent mistakes. That’s what most people do. It feels safe. But it defeats the purpose. You’re trading speed for safety when the whole point was speed.

The alternative is counterintuitive: give the AI broad permissions, but constrain the specific patterns that cause problems.

I run Claude Code with expansive access. It can execute commands, modify files, deploy to production. But I’ve built hooks that intercept specific dangerous patterns before they execute. When Claude tries to commit with —no-verify, a hook catches it and asks for explicit approval. When it tries to push without running tests, same thing. The AI can still do almost anything—it just can’t silently bypass the quality gates.

This is the insight: constraints don’t slow you down. The right constraints speed you up.

Think about climbing with a safety harness. The harness doesn’t prevent you from falling. You can still slip, lose your grip, make mistakes. What it prevents is catastrophe. You fall three feet instead of three hundred. That safety lets you climb faster, not slower. You take risks you’d never take without the harness.

My guardrails work the same way. Yesterday I made sixteen mistakes significant enough to require follow-up commits. But each mistake was small. The guardrails caught the patterns that would have created big problems: commits that bypassed validation, code that disabled safety checks, changes that would have broken the build. The mistakes that got through were the kind you fix in five minutes, not five hours.

This creates a compounding effect. Better constraints mean less rework. Less rework means more time for actual features. More features mean more opportunities for the AI to help. The whole system accelerates.

A 36% fix rate sounds bad until you realize what it replaced. Without guardrails, I’d have a lower fix rate—maybe 15%—but I’d also ship a third as much. The bugs that got through would be worse. I’d spend afternoons tracking down issues that a pre-commit hook would have caught in seconds. The total output would be lower, not higher.

People think of constraints as handicaps, speed bumps, things that prevent you from doing what you want. That’s the wrong frame. The right constraints don’t prevent you from doing things—they prevent you from doing the specific things that create rework. Everything else passes through untouched.

A sixty-line bash script intercepts every command Claude runs. If it’s not a git command, pass through. If it’s a git command without dangerous flags, pass through. Only if it’s a git commit or push with —no-verify does it intervene—and even then, it doesn’t block. It asks for confirmation. You can still bypass the checks if you really want to. You just can’t do it accidentally.

That’s maybe three milliseconds of overhead per command. In exchange, I never wonder whether Claude silently skipped the pre-commit hooks. I never audit the git history looking for commits that bypassed validation. I never clean up the mess from a change that should have been caught before it was committed.

The alternative—trying to get it right the first time—is both slower and less reliable. You still make mistakes. You just catch them later, when they’re more expensive to fix. Fast iteration with safety nets beats slow iteration without them.

When people get frustrated with AI coding assistants, they usually blame the AI. Not smart enough, not reliable enough, makes too many mistakes. But often the real problem is the absence of guardrails. The AI can move fast. You just need to make it safe to let it.

Build the constraints. The velocity follows.