All posts

Building AI guardrails for your dev teams

AI tools are everywhere in engineering now. Copilot in the IDE, ChatGPT in the browser, AI-powered code review bots in the PR pipeline. Most teams adopted these tools bottom-up — individual developers started using them, and leadership caught up later. The result is a lot of teams running AI-assisted development with zero guardrails.

That's not sustainable. Not because AI is dangerous, but because ungoverned AI usage creates inconsistency, security risks, and a false sense of productivity. Here's how I think about building guardrails that protect the team without killing the momentum.

Start with what leaves the building

The first guardrail isn't about code quality — it's about data exposure. Every time a developer pastes code into an AI tool, they're potentially sending proprietary logic, API keys, customer data, or internal architecture details to a third party.

Before anything else, establish clear rules:

  • Which tools are approved? There's a difference between Copilot (running in your IDE with enterprise data agreements) and pasting code into a random chatbot. Make the approved list explicit.
  • What can't be shared? Environment variables, customer data, internal API schemas, security configurations. Developers need a clear line, not a vague "use your judgment."
  • Where do credentials live? If AI tools are autocompleting .env files or suggesting hardcoded secrets, your secret management practices need to be airtight before AI amplifies the problem.

The biggest risk isn't that AI writes bad code. It's that a developer pastes sensitive context into a tool with no data retention guarantees.

Code review doesn't change — it gets more important

AI-generated code needs the same review rigor as human-written code. I'd argue it needs more, because AI-generated code has a specific failure mode: it looks plausible. It compiles, it passes a surface-level read, and it might even work for the happy path. But it can carry subtle bugs, security vulnerabilities, or patterns that don't match your codebase conventions.

Your code review process should account for this:

  • Reviewers should assume AI involvement. Not to be suspicious, but to be thorough. Read the logic, don't just skim the structure.
  • Check for AI-typical mistakes. Overly verbose code, unnecessary abstractions, deprecated API usage, security patterns that are "textbook correct" but wrong for your specific context.
  • Assertions and tests matter more. If a PR includes AI-generated logic, the tests need to be especially strong. Weak tests on AI code are how bugs ship.

Standardize the prompts, not just the output

One thing I've found effective is creating shared prompt templates for common tasks. Instead of every developer writing their own prompt for "generate a migration" or "write tests for this service," the team maintains a set of vetted prompts that encode your conventions.

This isn't about controlling how people use AI. It's about encoding institutional knowledge into the prompts so the output is consistent. When everyone's prompt includes "follow our existing error handling pattern in src/lib/errors" or "use our test factory pattern from tests/factories," the generated code fits the codebase instead of fighting it.

Here's a sample template a team might standardize for test generation:

Write Pest tests for the following service method.

Conventions:
- Build models via our factories in `tests/Factories` — never call Model::create() directly.
- Use `expect()` assertions. No `$this->assert*`.
- Mock outbound HTTP with `FakeHttp` in `tests/Support/FakeHttp.php` — not `Http::fake()`.
- Group related cases with `describe()`.
- Required coverage: happy path, each validation branch, and one failure mode per external dependency.
- Do not test framework behavior (Eloquent relations, built-in validation rules).

Method:
<paste method here>

It's not fancy — but it replaces four developers writing four different prompts and getting four different test styles back. Some teams go further and build these into CLI tools or IDE snippets. The overhead is minimal, and the consistency gain is real.

Set boundaries on where AI can operate

Not every part of your codebase should be fair game for AI-assisted development. I draw lines based on risk:

  • Low risk: UI components, utility functions, CRUD endpoints, test scaffolding. AI is great here. Let it rip.
  • Medium risk: Business logic, data transformations, API integrations. AI can draft, but a human needs to understand every line before it merges.
  • High risk: Authentication, authorization, payment processing, cryptography, data migrations. AI should assist with research and boilerplate at most. The core logic should be human-written and human-reviewed by someone who understands the domain.

This isn't about distrusting AI. It's about matching the level of scrutiny to the blast radius of a mistake.

Monitor and measure

You can't manage what you don't measure. Track what AI adoption actually looks like on your team:

  • What percentage of PRs include AI-generated code? You don't need exact numbers — even self-reported data helps.
  • Are bug rates changing? Not just total bugs, but the character of bugs. AI-typical bugs (plausible but wrong logic, missed edge cases) are worth tracking separately.
  • Is velocity actually improving? More code isn't more productivity. If AI is generating code that takes longer to review and debug, the net effect might be negative.

The human stays accountable

The most important guardrail is cultural: the developer who submits the code owns the code, regardless of how it was generated. AI is a tool, like a linter or a Stack Overflow answer. It doesn't own the commit, you do.

If your team internalizes one thing, make it this. AI doesn't reduce the need for understanding — it increases it. The developers who thrive with AI tools are the ones who use them to move faster through the parts they already understand, not to skip the parts they don't.

Build guardrails that reinforce that mindset, and AI becomes a genuine multiplier. Skip the guardrails, and you're just shipping code faster with less understanding. That's a debt that compounds.