Guardrail Coding

Programming with constraints, not prompts

February 6, 2026

What's the opposite of vibe coding?

About a year ago, Andrej Karpathy shared a thread about "fully giving in to the vibes" and letting AI handle the implementation. Vibe coding is fast and fun. My daughter and I make little web games with Claude where she describes what she imagines and Claude builds it, and we never look at the code. But most software has an existing legacy tech stack, a design system, a database schema, a team with preferences and coordination overhead, users who expect things to work consistently. If you've tried to vibe code anything beyond a weekend prototype, you've probably felt the wheels start to come off.

I've been writing about how to keep AI coding agents on the rails for a while now — how to onboard agents and apply quality gates, how to get more leverage with Markdown coding — and I keep landing on the same idea: the builders getting the best results from coding agents aren't writing better prompts. They're building better constraints.

I call this guardrail coding. I think of it as the opposite of vibe coding.

The problem: agents without constraints

Coding agents have only really worked for about the last year. Before that, "agents" were mostly vaporware — the models couldn't reason well enough, and tool use was bolted on rather than trained end-to-end. But with newer models and harnesses, coding agents can now reason and use tools in a loop until they complete fairly complex tasks.

But these agents are under-constrained. Ask one to build you a settings page and you might get purple buttons, random gradients, and a layout that looks nothing like the rest of your app. It's not stupid — it just doesn't know your constraints, because you haven't expressed them.

So how do we fix this? Most people understandably start in prompt space.

You might start adding constraints in chat: "use our brand colors", "follow our component patterns", "don't add new dependencies". When you find yourself repeating the same instructions a few times, you move them into custom instructions, or a Claude Project, or a .cursorrules file, or a CLAUDE.md.

But all of this is just guidance. You're asking an agent to follow a growing list of rules while also doing the actual work. It's paying attention to a lot at once, so it doesn't always listen to each particular rule. Sometimes it follows them. Sometimes it doesn't. There are no guarantees.

Guidance vs. guardrails

Here's the core idea: any constraint you care about can be expressed in one of two spaces, with very different properties.

Prompt space is where most people start. You describe what you want in natural language — in a chat message, in custom instructions, in a CLAUDE.md or .cursorrules file. This is guidance. It's easy to write, flexible, and better than nothing. But it's fuzzy. The agent might follow it. It might not.

Environment space is the alternative. Instead of asking the agent to follow a rule, you encode it as a check — a linter, a type checker, a test, a formatter. These are guardrails. Harder to set up, but deterministic, fast, and gives the agent concrete feedback it can act on.

Here's an example. Say you're building a front-end prototype and you want the AI to only use your product's colors — the color tokens from your design system and specific brand colors, not random hex colors.

You could put that in the prompt: "Only use colors from our design tokens. Never use raw hex colors." That will mostly work, but you'll find as you give it bigger tasks it will sometimes drop in a color like #6B4CE6. As the context window fills up with more instructions, the model's attention won't always follow all of them.

Or you could write a custom lint rule that flags any raw hex color in your codebase. Now the agent writes the code, the linter catches the violation in 20 milliseconds, and the agent fixes it — no tokens spent on enforcement, no hoping it remembered your instructions. The constraint just runs.

That's the shift from guidance to guardrails.

I wrote about a version of this idea last year as Quality Gates — type checkers, linters, formatters, and tests that agents must pass before finishing. Guardrail coding takes that further: not just checking code quality, but encoding your team's specific constraints into the environment where agents can sense and respond to them.

AI as interpreter vs. compiler

Most people use AI as an interpreter — you load up the context window with instructions and hope the model follows them at runtime, every time.

But you can instead choose to use AI as a compiler, i.e. run AI once at build time to generate deterministic checks we can run later at runtime.

For example, I don't need to be an ESLint expert to write custom lint rules that enforce rules for my agents. Claude is an ESLint expert, and can help "compile" my intent into specific rules.

I've experimented some with using Claude to test my website using Playwright, and it works pretty well. The "interpreter" approach would use AI at runtime to drive the tests. But the "compiler" approach is better — I can write test cases in Markdown and compile them offline to Playwright tests. Then the tests can run automatically with no AI involved, and only need to be updated if my test script changes.

Why guardrails work

Modern agents run their own OODA loop — observe, orient, decide, act. They write code, run checks, see errors, and fix them. They iterate in this loop for minutes or even hours until all constraints pass, similar to how a junior engineer uses compiler and IDE feedback to fix mistakes.

Guardrails plug directly into this loop. A lint rule that runs in 20 milliseconds gives the agent immediate, unambiguous feedback — at zero token cost. A prompt instruction, by contrast, sits in the context window competing for attention with everything else you've asked the agent to do. It's slower, more expensive, and hit-or-miss.

There's another benefit that's easy to overlook: guardrails are model-independent. If you've spent weeks tuning your prompts for a particular model, you know the pain of a new model release regressing all of your evals. Prompt-space constraints are fragile across model versions — you're always re-tuning. But a lint rule or type check doesn't care which model wrote the code. It just runs and returns a clear warning or error message to the model. Environment-space constraints are evergreen.

From design systems to guardrail systems

Design systems were always about constraints, not aesthetics. They say: these are the colors, these are the components, this is how spacing works. Don't deviate — or at least, not without a good reason.

The boundary between design and code is blurring, and a Figma board full of component mocks isn't very legible to coding agents. The agent can't read your Storybook. It doesn't know your internal naming conventions, your tech stack preferences, or which patterns your team has agreed on. Much of this context is private — it's not in the public training data used to train models like Claude or ChatGPT.

You can use a tool like Lovable, Cursor, or Claude to vibe code something super fast (it's fun!) — especially if you don't care much about the constraints it chooses. But don't be surprised when the result doesn't fit the constraints your design or engineering team has set. It can work well as a quick demo, but the path to production is pretty unclear. It's probably a throwaway.

I think design and engineering teams need to rethink what a "design system" means for the next era of software. Constraints are still very important — for good design, consistency, and usability for our customers. But the audience has changed — it's no longer just designers giving feedback on Figma or engineers interacting with Storybook variants. It's coding agents that need constraints expressed in formats they can consume and be held accountable to. I'd call this a guardrail system: the set of constraints, context, and checks that express how your team builds software.

Putting it into practice

If vibe coding works best for solo weekend projects or greenfield apps where AI can create a tech stack from scratch with no constraints or legacy code, and guardrail coding is the opposite of that — which customers would get the most value from it?

Most of the world's software doesn't look like a brand new Next.js app. Enterprises are fractals of dense constraints — business logic, custom configurations, compliance requirements, internal conventions — and most of those constraints aren't going away, even as the underlying platforms evolve. These are exactly the environments where AI coding has underdelivered so far, because no one has made those constraints legible to agents. Incumbents feel this most acutely today, but every sizable tech company will need the same thing — including the fastest-growing ones and companies yet to be born. If agents are writing your code autonomously, they need guardrails.

A few months ago, my wife nerd-sniped me on a hike into starting a company together — she has deep experience with enterprise software, and we both have a shared curiosity about how constraints and AI will interact in real-world software teams and custom platforms.

I'm having a lot of fun building Slider because I get to put some of this theory into practice with real customers and understand the messiness of their constraints. It's fun to see a customer's eyes light up on a call when they see a prototype that looks like their tech stack, not a generic one. If you're on a team where AI coding tools aren't delivering because they don't respect the constraints that matter to your product, I'd love to compare notes. Find me on X or LinkedIn, or sign up to follow along.