Why AI-Generated Code Needs Guardrails: Part 1 - The Problem

Want to implement solutions? Check out the Tutorial Series


AI coding assistants like GitHub Copilot, Claude Code, and Cursor have fundamentally changed how we write software. They're fast, they're helpful, and they can generate impressive amounts of code in seconds.

But there's a hidden cost that many teams are just beginning to discover.

The Promise vs. The Reality

When you first start using AI coding assistants, it feels like magic. Need a function? The AI writes it. Stuck on syntax? The AI completes it. Building a feature? The AI scaffolds it.

The velocity is intoxicating. You're shipping faster than ever before.

Then the problems start appearing.

What Research Reveals

Recent research into AI-generated code has uncovered some concerning patterns. While AI can write code quickly, that code exhibits specific quality issues that differ from human-written code:

4x More Code Clones

AI-generated code contains 4 times more code clones (duplicated code blocks) than human-written code. Why? Because AI assistants often generate similar solutions to similar problems, without understanding that you've already solved this problem elsewhere in your codebase.

Example scenario:

// File: userService.ts
// AI generated this yesterday
async function validateUserEmail(email: string): Promise<boolean> {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

// File: orderService.ts
// AI generated this today (doesn't know about userService.ts)
async function checkEmailFormat(email: string): Promise<boolean> {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

Two different functions, two different files, identical logic. Now you have two places to maintain when email validation requirements change.

Increased Code Churn

AI-generated code shows higher "code churn" - code that gets written and then quickly modified or deleted. This happens because:

  1. AI optimizes for "looks right" - The code compiles and seems to work, but doesn't handle edge cases
  2. AI lacks context - It doesn't know your team's patterns, architectural decisions, or existing abstractions
  3. AI can't test thoroughly - It generates code but can't validate it works in all scenarios

The Forgotten await Problem

One of the most common issues: AI forgets to add await keywords to async operations.

// AI-generated code (looks fine at first glance)
async function createUser(userData: UserData) {
  const user = userRepository.save(userData); // Missing await!
  sendWelcomeEmail(user.email); // user is a Promise, not a User
  return user;
}

This compiles. TypeScript doesn't complain (depending on your settings). But at runtime? Race conditions, undefined values, and mysterious bugs.

Unused Variables Everywhere

AI loves creating variables "just in case" you might need them:

function processOrder(order: Order) {
  const orderId = order.id; // Created but never used
  const userId = order.userId; // Created but never used
  const items = order.items; // Created but never used

  return order.total;
}

Harmless? Maybe. But it clutters your code, confuses future developers, and makes the codebase harder to maintain.

The Real Cost: Maintenance Debt

The initial velocity gain is real. You write features faster with AI assistance.

But here's what happens 6 months later:

  • Code reviews take longer - Reviewers have to spot AI mistakes humans wouldn't make
  • Bugs are harder to track - Duplicated logic means bugs appear in multiple places
  • Refactoring becomes risky - You're never sure which "clone" is the canonical version
  • Onboarding is harder - New developers see inconsistent patterns and get confused

The velocity gain at the start gets consumed by maintenance cost later.

It's Not the AI's Fault

Here's the thing: AI coding assistants are working exactly as designed.

They're trained on millions of code examples. They understand patterns. They can generate syntactically correct code. They're incredibly useful tools.

But they're not magic. They're tools that work best within specific constraints.

Think of it like power tools in construction:

  • A circular saw can cut wood 10x faster than a hand saw
  • But without proper safety guards, measuring guides, and technique, you get dangerous or imprecise cuts
  • Professional woodworkers don't blame the saw - they build jigs, use guides, and follow safety protocols

AI coding assistants need the same approach: structured guardrails that help them work safely and effectively.

What AI Needs to Succeed

Based on research and real-world experience, AI coding assistants work best when you provide:

1. Clear Structure

AI needs to understand your project layout. When files follow consistent patterns, AI can:

  • Find existing abstractions instead of creating duplicates
  • Understand where different types of code belong
  • Generate code that fits your architecture

2. Consistent Patterns

AI learns from your existing code. When your codebase has consistent patterns:

  • AI suggestions match your style
  • Code reviews are easier (deviations stand out)
  • The codebase feels cohesive, not like 5 different developers wrote it

3. Strong Guardrails

Automated checks catch AI mistakes before code review:

  • ESLint catches forgotten await, unused variables, unsafe operations
  • TypeScript strict mode prevents type-unsafe operations
  • Tests verify the code actually works
  • CI/CD ensures nothing broken gets merged

4. Explicit Documentation

AI can't read your mind. Good documentation provides:

  • Context about why decisions were made
  • Explanations of patterns and conventions
  • Examples of correct usage
  • Warnings about common mistakes

The Solution: The AI Programming Toolkit

This is where the AI Programming Toolkit comes in.

It's a collection of 9 modules that provide exactly these guardrails:

  1. ESLint Configurations - 24 pre-configured setups for different collaboration patterns
  2. Git Conventions - Commit and branch standards that help AI understand project history
  3. Project Structure - Templates that give AI clear context
  4. Documentation Standards - Patterns that provide AI with the context it needs
  5. Testing Strategies - Test patterns that catch AI mistakes
  6. TypeScript Patterns - Type safety approaches that prevent unsafe operations
  7. CI/CD Automation - Automated checks that enforce standards
  8. Prompt Engineering - Techniques for getting better AI suggestions
  9. Code Review - Checklists for reviewing AI-generated code

Want to dive deeper into the research and patterns? Continue to Part 2: The Research →

Ready to start implementing? Jump to the Tutorial Series

What's Next?

In Part 2, we'll explore the research behind different AI collaboration patterns. You'll learn:

  • Why "AI-AI" collaboration is different from "AI-Human" collaboration
  • The evidence-based approach to choosing guardrails
  • How different teams need different configurations

In Part 3, we'll discuss the philosophy behind 24 ESLint configurations and why context-specific tooling matters more than one-size-fits-all solutions.


Questions or thoughts? The AI Programming Toolkit is open source and actively seeking contributors. Share your experiences with AI-assisted development - what patterns have worked for your team?