Tutorials

Vibe Coding: A Guide for Engineers and Teams

What is vibe coding?

Vibe coding is an approach to development where the engineer describes intent and AI generates the code. In a professional context, it's systematic collaboration, not a replacement for programming: the engineer defines architecture, rules, and quality gates, and AI executes the implementation within those constraints. The key difference from amateur vibe coding is enforcement — automated checks that guarantee the quality of AI-generated code.

TL;DR

  • -Vibe coding for engineers means systematic collaboration with AI at the level of architecture, process, and enforcement — not just 'AI writes your code for you'
  • -Four stages of evolution: chaotic prompting → prompt engineering → context engineering → enforcement (quality gates, pre-commit hooks)
  • -Architecture: Brain (CLAUDE.md, rules files) + Hands (agents, MCP, skills) + Conscience (hooks, linters, tests) — conscience matters most
  • -Rules-driven development: rules in the repository replace verbal agreements and teach AI the project's context
  • -Teams benefit from shared rules, structured code review for AI-generated code, and velocity/quality metrics — individual prompt hacks don't deliver this

Andrej Karpathy coined the term in February 2025: “I just see things, say things, run things, and copy paste things, and it mostly works.” A month later, vibe coding was a meme. Six months later, it was an approach reshaping professional development.

The problem is how people understand it. Most articles describe vibe coding as “describe it in words — AI writes the code.” That gives the impression of autocomplete on steroids. Maybe for beginners. Not for engineers.

Vibe coding for an engineer means AI handles the routine implementation, architectural decisions stay with the human, and quality gets verified by automated hooks. “AI writes code by your rules, and those rules are code.”

Here are the concrete approaches, tools, and patterns. For people who write code professionally and want to fold AI into their process — no magic, no marketing.

What Vibe Coding Is (and Isn’t)

A Definition for Engineers

Vibe coding is an approach to development where the engineer focuses on intent and architecture, and AI generates the implementation. The key word is “engineer.” Not “user.” Not “prompter.”

Three components make vibe coding an engineering approach:

  1. Project context is encoded in files (CLAUDE.md, .cursorrules), not in the developer’s head
  2. Quality rules are automated, not verbal: hooks, linters, tests
  3. AI operates within constraints: architecture, patterns, and dependencies are defined up front

Without these three components, vibe coding is just prompting. With them, it’s an engineering process with AI acceleration.

What It Isn’t

Not autocomplete. Copilot finishes a line. Vibe coding is when AI implements an entire module, following the project’s rules.

Not “I’m not a programmer, but…”. Articles about “build an app with no coding skills” are about something else. Vibe coding for engineers assumes you understand the code AI generates. You’re the architect, AI is the contractor.

Not a replacement for code review. AI-generated code needs review — often more thorough than human-written code. AI confidently writes code that compiles and passes tests but violates system invariants.

Not a silver bullet. Vibe coding speeds up implementation — not design, not debugging complex distributed systems, not domain understanding.

Why Engineers Are Skeptical — and When They Change Their Minds

The skepticism is justified. The first experience usually goes like this: you ask AI to write a function, get something that works, and spend an hour polishing it. Net savings: minus thirty minutes.

The shift happens when an engineer moves from one-off requests to a system:

  • The first time they set up CLAUDE.md — and Claude stopped suggesting patterns the project doesn’t use
  • The first time a pre-commit hook caught AI-generated code without tests — and it became clear why enforcement matters
  • The first time they committed a rules file to the repository — and a teammate got the same context without a verbal explanation

The system works. Individual prompts don’t always.

Evolution: From Chaos to System

Vibe coding has gone through four stages. Most teams are stuck on the first or second.

Stage 1: Chaotic Prompting

“Write me a sorting function,” “Make a React form component,” “Fix this bug.” Every request starts from scratch. No context. Unpredictable results.

Characteristics:

  • Every prompt is isolated
  • The result depends on phrasing
  • No repeatability: the same request produces different code each time
  • The engineer spends more time on the prompt than they would writing the code by hand

This isn’t vibe coding. This is chatting with AI.

Stage 2: Prompt Engineering

System prompts. Few-shot examples. Chain-of-thought. The engineer formalizes how they communicate with AI.

You are a senior TypeScript developer.
Follow functional programming patterns.
Use zod for validation.
Return Result<T, Error> instead of throwing.

Characteristics:

  • Prompts are structured and reusable
  • Quality improves thanks to context in the prompt
  • But the prompt lives in the developer’s head or personal notes
  • No versioning, no team synchronization

Better than chaos. But a 500-token prompt doesn’t convey the context of a 100,000-line project.

Stage 3: Context Engineering

Project context gets encoded into files. CLAUDE.md, .cursorrules, .windsurfrules — these files load into every AI session and give the model full context: stack, architecture, conventions, prohibitions.

# CLAUDE.md
## Stack
- TypeScript 5.4, strict mode
- React 19 + TanStack Router
- Drizzle ORM + PostgreSQL
- Vitest for testing

## Conventions
- No default exports
- Zod schemas co-located with API routes
- Error handling: Result<T, Error>, never throw in business logic
- File naming: kebab-case

Characteristics:

  • Context is versioned in git
  • Every team member works with AI in the same context
  • AI “knows” the project: stack, conventions, architecture
  • Results are more stable, but still not guaranteed

This is already vibe coding. But without guarantees.

Stage 4: Enforcement

Rules are enforced, not just described. Pre-commit hooks block a commit if the code fails checks. CI/CD rejects a PR with violations. AI can’t bypass quality gates.

# .husky/pre-commit
npx lint-staged

# lint-staged.config.js
export default {
  '*.{ts,tsx}': [
    'eslint --fix --max-warnings 0',
    'prettier --write',
    () => 'tsc --noEmit',
    'vitest related --run',
  ],
};

Characteristics:

  • Quality is guaranteed automatically, independent of discipline
  • AI generates any code it wants — bad code doesn’t get through
  • The cycle: AI generates → hook rejects → AI fixes → hook accepts
  • The engineer verifies the result, not every line of quality

This is mature vibe coding. AI writes. The system checks. The engineer stays in control.

The Vibe Shift: Why 2025–2026 Is the Turning Point

Three factors converged:

  1. Models became good enough. Claude Opus 4.8, GPT-5.5, and Gemini 3.5 Flash generate code that passes tests on the first or second try. Just two years ago, this required 5–10 iterations.

  2. Tools matured. Claude Code (CLI + desktop app + Agent SDK), Cursor 3.5, Devin Desktop, OpenAI Codex — not prototypes, but production-ready platforms supporting rules, agents, hooks, and cloud delegation.

  3. Enforcement became standard. Pre-commit hooks, CI/CD with AI checks, automated testing — the infrastructure for controlling AI-generated code exists and works.

The shift from “AI as an assistant” to “AI as a contractor under control” — that’s the vibe shift.

The Architecture of Systematic Vibe Coding

Systematic vibe coding rests on three components. The Vibe Framework calls them “the three pillars” — a useful mental model.

Brain: Context and Rules

The brain is everything AI knows about the project before it starts working.

Context files:

  • CLAUDE.md — for Claude Code. Loads automatically on every run
  • .cursor/rules/*.mdc — for Cursor (the current format since 2025; the legacy .cursorrules is still supported but ignored in Agent mode)
  • .windsurfrules — for Devin Desktop (ex-Windsurf)
  • copilot-instructions.md — for GitHub Copilot

What to include:

# Project Context
## Commands
npm run dev          # Dev server
npm run test         # Run tests
npm run build        # Production build

## Architecture
- Monorepo: Turborepo
- API: tRPC + Drizzle
- Frontend: React 19 + TanStack Router + TanStack Query
- Database: PostgreSQL 16

## Conventions
- Named exports only
- Barrel files: src/features/*/index.ts
- Tests: co-located (*.test.ts next to source)
- Errors: never throw in business logic, use Result<T, E>
- SQL: raw queries through Drizzle, no query builder for complex joins

## Do NOT
- Add dependencies without explicit approval
- Use default exports
- Put business logic in API route handlers
- Use any/unknown without explicit reason in comment

What NOT to include:

  • The obvious (how to write functions in TypeScript)
  • Temporary decisions (TODOs, hacks, “we’ll fix it later”)
  • Excessive context (every extra token reduces the model’s attention to everything else)

The optimal CLAUDE.md size is 100–300 lines. Longer, and the model loses focus. Shorter, and there’s not enough context.

Hands: Tools and Agents

The hands are how AI interacts with the project.

Tools:

  • Reading/writing files
  • Running shell commands
  • Searching the codebase (grep, glob)
  • Git operations
  • MCP servers (external integrations: GitHub, databases, monitoring)

Agents:

  • Subagents in Claude Code — isolated AI threads with separate context
  • Agents Window in Cursor 3 — parallel agents, local and in the cloud
  • Devin Local in Devin Desktop — multi-step operations (Cascade deprecated as of July 2026)

Skills (Claude Code):

  • Reusable commands: /commit, /review, /test
  • Defined as markdown files
  • Include a specific prompt and a set of allowed actions

Example skill file:

# /review
Review the current git diff for:
1. Logic errors
2. Missing error handling
3. Deviation from project conventions (see CLAUDE.md)
4. Missing tests for new functions

Output: list of issues with file:line references.
Do NOT auto-fix — only report.

Conscience: Enforcement and Quality Gates

The conscience is the most important component. Without it, the brain and the hands generate plausible-looking but not reliably quality code.

Pre-commit hooks:

  • Lint (eslint/biome) — style and potential errors
  • Format (prettier/biome) — consistent formatting
  • Type-check (tsc —noEmit) — type safety
  • Test (vitest related) — tests for changed files

CI/CD:

  • Full test run
  • Coverage check (coverage threshold)
  • Security audit (npm audit, snyk)
  • Bundle size check

Additional checks:

  • Architectural rules (eslint-plugin-boundaries — banning imports between layers)
  • Dependency check (no adding dependencies without approval)
  • Commit message format (conventional commits)

Agent isolation (the 2026 norm):

  • Each agent works in a separate worktree/branch — changes don’t overlap until an explicit merge
  • Permission modes: allow-deny lists for tools, network controls for agents making external requests
  • MCP governance: server allowlists, OAuth scopes, banning dangerous tools at the config level
  • Agent logs as a PR artifact: what it read, what it changed, what commands it ran, which tests passed

AI review gate (a recommended practice):

  • Automated AI review of every PR before human code review: Bugbot (Cursor), Codex Security (OpenAI)
  • Prompt-injection gate: scanning issues, PR comments, doc pages, and MCP outputs for injections
  • AI-written code goes through the same SAST checks as human-written code (snyk, semgrep, bandit)

Why the conscience matters most: AI confidently generates code that looks correct. Without automated checks, that code lands in main. With them, it doesn’t — not until it passes every gate. AI fixes its own mistakes fast, given concrete feedback from a linter or a test.

The cycle works like this:

AI generates code
  → pre-commit hook runs lint
    → lint finds an unused import
      → AI removes the import
        → hook runs tests
          → a test fails (missed an edge case)
            → AI adds handling
              → all checks pass
                → commit created

In agentic mode (Claude Code, Cursor Composer), this cycle can happen without manual intervention — the agent fixes its own mistakes based on hook output. In interactive mode, the engineer sees the result of each step and decides whether to commit.

Project Phases with AI

AI changes both the implementation and the order of work. A linear waterfall and chaotic agile mix equally poorly with AI. An effective process is phased.

Phase 1: Specification

Before generating code — a specification. AI works better with a clear description than with a vague “make it good.”

## Feature: Rate Limiter Middleware

### Behavior
- Limit requests per IP: 100/minute for API, 20/minute for auth endpoints
- Return 429 with Retry-After header when exceeded
- Use sliding window algorithm
- Store counters in Redis (ioredis client from existing infra)

### Interface
```typescript
type RateLimiterConfig = {
  windowMs: number;
  maxRequests: number;
  keyGenerator: (req: Request) => string;
};

function createRateLimiter(config: RateLimiterConfig): Middleware;

Constraints

  • No new dependencies (use existing ioredis)
  • Must handle Redis connection failure gracefully (allow requests, log warning)
  • Tests: unit (mock Redis) + integration (real Redis via testcontainers)

A specification is a contract between the engineer and AI. The more precise the contract, the fewer the iterations.

### Phase 2: Design System and Tokens

For frontend work — design tokens before implementation. AI with tokens generates a consistent UI. AI without tokens hardcodes values.

```typescript
// tokens.ts
export const spacing = {
  xs: '0.25rem',   // 4px
  sm: '0.5rem',    // 8px
  md: '1rem',      // 16px
  lg: '1.5rem',    // 24px
  xl: '2rem',      // 32px
} as const;

export const colors = {
  primary: 'hsl(222, 47%, 11%)',
  accent: 'hsl(43, 74%, 54%)',
  surface: {
    base: 'hsl(0, 0%, 4%)',
    raised: 'hsl(0, 0%, 7%)',
    overlay: 'hsl(0, 0%, 10%)',
  },
} as const;

In the rules file:

## Design System
- Use tokens from src/tokens.ts — NEVER hardcode colors, spacing, font sizes
- Components must accept className prop for composition
- No inline styles except dynamic values (e.g., width from props)

Phase 3: Decomposition

A big task → epics → features → tasks. Every task is atomic: one prompt, one commit, one verifiable unit.

Epic: User Authentication
├── Feature: Email/password registration
│   ├── Task: Registration form component
│   ├── Task: API route POST /auth/register
│   ├── Task: Email verification flow
│   └── Task: Tests for registration
├── Feature: Login flow
│   ├── Task: Login form component
│   ├── Task: API route POST /auth/login
│   ├── Task: Session management
│   └── Task: Tests for login
└── Feature: Password reset
    ├── Task: Reset request form + API
    ├── Task: Reset confirmation + token validation
    └── Task: Tests for reset flow

Wave-based parallelism: tasks without dependencies run in parallel. One subagent on the registration form, another on the API route. Both work from the same CLAUDE.md.

Phase 4: Implementation

Every feature goes through a cycle: brainstorm → build → test → commit.

Brainstorm: discuss the approach with AI before generating code. What edge cases? What trade-offs? What existing utilities should be reused?

Build: AI generates the code. Don’t hand-edit at this stage — let AI finish.

Test: AI generates tests. Review the tests before running them — tests are a specification. If the tests don’t cover an edge case, ask for it to be added before implementation.

Commit: Automated: pre-commit hooks, conventional commit message.

Phase 5: Verification

AI generates the tests — the engineer verifies them. Not the other way around.

What to check in AI-written tests:

  • Do the tests check behavior, not implementation? (mocking internal functions is bad)
  • Are edge cases covered? (null, empty, concurrent, timeout)
  • Any tautologies? (a test that mirrors the implementation instead of verifying it)
  • Are assertions specific enough? (toEqual vs toBeTruthy)

Tools for Professional Vibe Coding

Claude Code

Anthropic’s flagship agent. Available as a CLI (terminal), desktop app, and IDE plugin; one account, shared context.

Desktop app (as of April 2026): redesigned for parallel sessions. A sidebar for managing multiple agents, drag-and-drop layout, a built-in terminal and file editor, a fast diff viewer. Parity with the CLI: plugins, MCP, skills work the same in both modes.

Routines (cloud automations): saved tasks that run in Anthropic’s cloud — no need to keep a laptop on. Triggers: schedule, a GitHub event, Slack, etc.

Rules: CLAUDE.md at the project root. Hierarchy: ~/.claude/CLAUDE.md (global) → project CLAUDE.md.claude/ directory with additional rules.

Agents: Subagents — markdown files in .claude/agents/. Each agent is a specialized AI with isolated context. Parallel agents run in separate worktrees/branches.

Skills: Reusable commands in .claude/commands/. Invoked via /skill-name.

Hooks: Pre/post-tool hooks on every lifecycle step of an agent. Example: run tests automatically after every git commit; log the command before every Bash call.

Agent SDK (Python/TypeScript): the same agent loop that powers Claude Code internally — tools, context, hooks, subagents, MCP, permissions — as a library for your own pipelines.

Non-interactive / headless: claude -p, JSON output, stream JSON, schema output, --max-turns. Used in CI/CD and automations without interactive input.

MCP: Model Context Protocol — integration with external services. GitHub, Notion, databases, monitoring — via a standard protocol.

// .mcp.json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"]
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "postgresql://..."
      }
    }
  }
}

Cursor

A VS Code-based IDE. Version 3.5 (May 2026) is a full-fledged agentic platform with cloud and marketplace support.

Rules: .cursor/rules/*.mdc — separate .mdc files in the .cursor/rules/ directory. They support YAML frontmatter with activation modes (always/auto-attach/agent-requested/manual). The legacy .cursorrules file at the project root is still read, but ignored in Agent mode.

Composer: Agentic mode. Creates/edits multiple files in a single request.

Agents Window: Parallel agent execution locally, in worktrees, in the cloud (isolated cloud VMs with a terminal and browser), and over remote SSH. Agents create PRs and work asynchronously.

Cloud Agents (v3.5): agents in cloud VMs with full access to a terminal, browser, and multiple repositories in parallel. Results come back into the IDE.

Bugbot: AI review on every PR. Finds bugs and potential issues automatically (~90 second average cycle). Included in the team plan.

Customize page: a single management page for plugins, skills, MCP, subagents, rules, commands, and hooks — at the user, team, or workspace level. A team marketplace for sharing configurations.

Models: Supports Claude, GPT, Gemini. You can switch between them per task.

Devin Desktop (ex-Windsurf)

As of June 2, 2026, Windsurf was renamed Devin Desktop: Cognition folded the IDE into its agentic ecosystem via a standard over-the-air update. All Windsurf settings migrated automatically.

Agent Command Center (Spaces): a Kanban interface for managing local and cloud agents from one place. Running multiple tasks in parallel is the default mode.

Devin Local: a new local agent that replaced Cascade (end-of-life July 1, 2026). Up to 30% higher token efficiency, subagent support — parallel task processing that Cascade didn’t have.

Memories: Persistent context across sessions carried over.

SWE-1.6: Cognition’s own coding model (released April 2026). Runs on top of base models; included free in paid plans. Less overthinking, more parallel tool calls.

OpenAI Codex

OpenAI’s agentic coding platform. A single brand for CLI, desktop app, and cloud tasks.

Codex CLI: a local agent that runs in the terminal. Reads, edits, and runs code. Open source, written in Rust. A direct alternative to Claude Code CLI.

Codex App (Mac + Windows): a desktop app for coordinating multiple parallel agents. Worktree, automation, and Git management. The Windows version shipped in May 2026.

Codex Cloud / Web tasks: background agentic tasks in OpenAI’s cloud environment. Delegation without tying up a local machine.

Codex Security: AI-driven code security analysis. A local plugin and a cloud scan with a repo-specific threat model, validation evidence, and suggested fixes.

Models: runs on GPT-5.5 — the first fully retrained base model with agentic-first training (released April 2026).

Positioning: if Claude Code is a terminal-first Unix tool, Codex is OpenAI’s full-stack agentic platform with a built-in security layer.

Comparing Approaches

AspectClaude CodeCursorDevin DesktopOpenAI Codex
InterfaceCLI + DesktopIDE (VS Code fork)IDE (VS Code fork)CLI + Desktop + Cloud
Rules filesCLAUDE.md, .claude/.cursor/rules/*.mdc.windsurfrules— (context via CLI flags)
AgentsSubagents + RoutinesCloud Agents + Agents WindowDevin Local + cloud agentsParallel threads + Cloud tasks
MCP supportFullPartialPartialLimited
CI/CD integrationNative (CLI, GitHub Actions)Via terminalVia terminalGitHub bot, webhooks
HooksPre/post-tool (lifecycle)NoNoNo
Skills/CommandsYes (.claude/commands/)No (snippets)NoNo
Headless modeYes (Agent SDK, non-interactive)NoNoPartial (API)
Security gateNo (external tools)Bugbot (PR-level)NoCodex Security
Cost$20–200/mo or API$20/mo (Pro)$20/mo (Pro)$20/mo or API
Best forCLI-oriented work, backend, DevOpsFrontend, IDE-based work, teamsMulti-agent command centerOpenAI stack, security focus

Common Tools

Regardless of IDE/CLI:

  • Pre-commit hooks: husky + lint-staged (JS/TS), pre-commit (Python), lefthook (universal)
  • Linters: eslint, biome (JS/TS); ruff (Python); clippy (Rust)
  • Formatters: prettier, biome (JS/TS); black, ruff (Python); rustfmt (Rust)
  • Type checking: tsc —noEmit (TS); mypy, pyright (Python)
  • Testing: vitest (JS/TS); pytest (Python); cargo test (Rust)
  • CI/CD: GitHub Actions, GitLab CI — running all checks on push/PR

Vibe Coding on a Team

Individual vibe coding is a skill. Team vibe coding is a process. The difference is fundamental.

Shared Rules

Rules files get committed to the repository. Every team member — and every AI assistant — works from the same context.

repo/
├── CLAUDE.md              # Claude Code users
├── .cursor/rules/         # Cursor users (.mdc files with frontmatter)
├── .windsurfrules         # Devin Desktop users (format survived the rebrand)
├── .eslintrc.js           # Enforcement (all)
├── .husky/pre-commit      # Enforcement (all)
└── vitest.config.ts       # Testing (all)

Rule of thumb: if something matters to AI, it matters to a human too. Rules files replace verbal agreements. A new developer opens CLAUDE.md and understands the conventions without reading 50 pages of Confluence.

Code Review for AI-Generated Code

AI-generated code needs a specific kind of review. Checklist:

Architecture:

  • Does the code follow the project’s established patterns?
  • No new abstractions where an existing one would do?
  • Is it in the right layer? (AI loves mixing UI and business logic)

Dependencies:

  • No new dependencies added without discussion?
  • Do the utilities duplicate existing ones? (AI often writes a helper without knowing one already exists)

Edge cases:

  • Is error handling real, not a catch-all?
  • No race conditions in async code?
  • Is input validation in place?

Tests:

  • Do the tests check behavior, not implementation?
  • Are there negative tests (what should NOT work)?

“Smell” of AI-generated code:

  • No excessive comments explaining the obvious?
  • No over-engineering (3 abstractions for one use case)?
  • No stubs with // TODO: implement?

Onboarding: A New Developer + AI

Steps for a new team member:

  1. Read CLAUDE.md — it’s both documentation and AI configuration at once
  2. Run npm test and npm run lint — confirm enforcement works
  3. Do the first task with AI — with a mentor showing the workflow
  4. Add a rule — if AI did something that had to be corrected, add a rule to the rules file

Rule of thumb: every bug from AI → a new rule in CLAUDE.md. The file grows organically from real problems, not theoretical best practices.

Metrics

What to measure to gauge the effect of vibe coding:

MetricHow to measureWhat to watch for
VelocityStory points/week, PRs mergedGrowth in the first month, then stabilization
Time-to-mergeTime from PR creation to mergeShould decrease (code is cleaner thanks to hooks)
Defect rateBugs per 1,000 linesWatch that it doesn’t grow (AI code can be fragile)
Test coverage% coverageAI generates tests well — coverage grows
Rule additionsRules/week in CLAUDE.mdActive growth = the team is learning to work with AI
AI cost$/developer/monthTypical range: $100–250/month with daily use
Human intervention rateManual edits to AI PRs / total AI PRsDecreasing = the rules file is working
Rework rateReverted AI PRs / total AI PRsIncreasing = insufficient enforcement or spec
Cost per merged PRAI spend / PRs mergedEfficiency of the agentic workflow
Security findings (AI code)Confirmed SAST hits in AI PRsShould trend toward zero with good rules

Team Anti-Patterns

“Everyone has their own prompt.” Developers use personal system prompts instead of shared rules. Result: inconsistent code, different patterns within the same project. Fix: a rules file in the repo, personal settings only extend it, they don’t override it.

“AI will handle everything.” The team stops making design and architectural decisions, relying on AI. AI generates “something that works” without systemic thinking. Result: architectural chaos within 2 months.

“Don’t touch it — it works.” AI-generated code doesn’t get refactored because “it works.” Technical debt accumulates unnoticed.

“One tool for everyone.” Forcing the entire team onto a single AI tool. Some people are more productive in a CLI, others in an IDE. What matters is shared rules, not a shared tool.

Rules-Driven Development

Rules-driven development (RDD) is an approach where AI behavior is governed by declarative rules, not ad-hoc prompts.

Rules Instead of Advice

Advice: “Please use named exports.” Rule: NEVER use default exports. Named exports only. This is enforced by eslint rule import/no-default-export.

The difference:

  • AI can ignore advice (especially with a long context)
  • A rule is stated imperatively and backed by enforcement
  • A rule includes the “why” — AI follows rules better when it understands the reason

The Structure of a Rule

Every rule contains three elements:

## Error Handling
**WHAT:** Use Result<T, E> pattern for business logic errors. Never throw.
**WHY:** Thrown exceptions bypass TypeScript type system. Callers don't know
a function can fail until runtime.
**WHEN:** All functions in src/domain/ and src/services/.
API route handlers can throw — framework catches them.

Examples of Rules Files

Backend (Node.js/TypeScript):

## API Routes
- Route handlers in src/routes/ — thin, only validation + delegation
- Business logic in src/services/ — never import from routes
- Database queries in src/repositories/ — never import from services directly, use interfaces

## Error Handling
- Domain errors: src/errors.ts, extend AppError base class
- Services return Result<T, AppError>, never throw
- Route handlers: try/catch at top level, map AppError to HTTP status

## Database
- Migrations in src/db/migrations/ — generated by drizzle-kit
- Never modify database schema without migration
- All queries use parameterized statements (drizzle handles this, but verify in raw SQL)

## Testing
- Unit tests: *.test.ts next to source file
- Integration tests: src/__tests__/integration/
- Mock external services, never mock internal modules
- Test file structure: describe(module) > describe(function) > it(behavior)

Frontend (React/TypeScript):

## Components
- Feature components: src/features/{name}/components/
- Shared components: src/components/shared/
- No prop drilling beyond 2 levels — use context or composition
- Every component that accepts children must type them as React.ReactNode

## State Management
- Server state: TanStack Query (no Redux for API data)
- Local UI state: useState/useReducer
- Global UI state (theme, sidebar): Zustand store in src/stores/

## Styling
- Tailwind CSS — no CSS files, no CSS-in-JS
- Use tokens from tailwind.config.ts (colors, spacing, breakpoints)
- No arbitrary values in Tailwind classes ([32px]) — add to config if needed
- Responsive: mobile-first (sm: md: lg:)

## Forms
- React Hook Form + Zod
- Schema in src/schemas/ — shared between frontend validation and API
- Error messages in src/i18n/ — never hardcode strings

Enforcement via Hooks

Rules in CLAUDE.md are soft enforcement. Hooks are hard enforcement. Combined:

// lint-staged.config.js
export default {
  '*.{ts,tsx}': [
    // Style and patterns
    'eslint --fix --max-warnings 0',
    'prettier --write',
    // Type safety
    () => 'tsc --noEmit',
    // Tests for changed files
    'vitest related --run',
  ],
};

ESLint rules that are especially useful with vibe coding:

// eslint.config.js (flat config)
export default [
  {
    rules: {
      'import/no-default-export': 'error',
      'no-console': ['error', { allow: ['warn', 'error'] }],
      '@typescript-eslint/no-explicit-any': 'error',
      '@typescript-eslint/no-unused-vars': 'error',
      'no-restricted-imports': ['error', {
        patterns: [{
          group: ['../../../*'],
          message: 'Avoid deep relative imports. Use path aliases.',
        }],
      }],
    },
  },
];

AI generates code with any? ESLint blocks it. AI adds console.log for debugging? ESLint blocks it. AI makes a deep relative import? ESLint blocks it. AI fixes it — automatically.

Markers in Code for AI

Markers are comments in the code that give AI extra context:

// AI:CONTEXT — This module handles rate limiting.
// See ADR-007 for why we use sliding window instead of fixed.

// AI:INVARIANT — maxRequests must never exceed 1000 per window.
// This is a hard business rule, not a technical limitation.

// AI:CAREFUL — This function is called from 15+ places.
// Changing its signature requires updating all callers.

// AI:NO-MODIFY — Generated by protobuf. Do not edit manually.

Markers aren’t comments for humans. They’re metadata for AI. They help the model understand what not to touch, what matters, and where to look for context.

Real-World Cases

Solo: MVP in 2 Weeks

Context: A solo developer building a SaaS for API endpoint monitoring. Stack: Next.js 15, Drizzle ORM, PostgreSQL.

Approach:

  • CLAUDE.md: 180 lines (stack, conventions, DB schema, API contracts)
  • Pre-commit: eslint + prettier + tsc + vitest
  • Claude Code for implementation. Each feature — a separate prompt with a clear spec

Result:

  • 14 days to a working MVP
  • 47 API endpoints
  • 89% test coverage
  • One serious bug in production (a race condition in the health check — AI didn’t account for concurrent requests)

Key takeaway: Specifying each feature took 20–30 minutes. AI implementation — 5–15 minutes. A 2:1 ratio — the spec costs more than the code. That’s normal.

A Team of 5: Legacy Refactor

Context: An Express.js monolith, 80,000 lines, no types, 12% test coverage. Goal: migrate to TypeScript and split it into modules.

Approach:

  • Shared CLAUDE.md with migration rules: how to convert routes, how to add types, which patterns to use
  • Each developer takes a module and converts it with AI
  • Pre-commit hooks: strict TypeScript (no-any), eslint, tests
  • Weekly rules review: updating CLAUDE.md based on problems found

Metrics (3 months):

MetricBeforeAfter
TypeScript coverage0%78%
Test coverage12%61%
Bugs/month (prod)146
Deploy time45 min12 min
Rules in CLAUDE.md0340 lines

Key takeaway: CLAUDE.md grew from 50 to 340 lines over 3 months. Every rule was the result of a real problem. By month three, AI made fewer mistakes: the rules file covered all the project’s typical patterns.

Enterprise: AI in an Existing Process

Context: A fintech company, 40 developers, strict compliance. You can’t “just start using AI.”

Approach (6 months):

Months 1–2: pilot with 5 developers on a non-critical internal tool. Goal — prove safety and effectiveness.

Months 3–4: expand to 15 people. Shared rules. Mandatory security review for AI-generated code. Metrics.

Months 5–6: 30+ developers. AI-generated code goes through the same checks as human-written code. Plus: a SAST scanner on AI-generated PRs.

Result:

  • Velocity: +35% (measured as PRs merged per sprint)
  • Defect rate: unchanged (enforcement is working)
  • Security incidents from AI-generated code: 0 (SAST + manual review)
  • Adoption: 82% of developers use AI daily

Key takeaway: Enterprise adoption isn’t a technical problem. It’s change management. Rules + enforcement + metrics = the arguments that convince management.

Problems and Limitations

Vibe coding has real problems. Knowing them matters more than knowing the benefits.

AI-Generated Technical Debt

AI optimizes for “works right now,” not “easy to maintain in a year.” Typical problems:

  • Copy-paste instead of abstraction. AI copies a pattern 5 times instead of creating a reusable function. Every copy works. Maintaining 5 copies doesn’t.
  • Over-engineering. The flip side: AI creates an abstraction for a single use case. A factory for an object that’s only ever created in one place.
  • Inconsistent patterns. On Monday AI used one approach for error handling, on Friday — another. Both work. The codebase turns into a zoo.

Mitigation: a rules file + architectural linting (eslint-plugin-boundaries) + regular refactoring.

”Works, but Why?”

AI generates code that passes tests. The developer merges it. A month later — a bug. The developer opens the code and doesn’t understand how it works, because nobody reviewed the implementation, only the result.

Rule of thumb: if you can’t explain every line, don’t merge it. AI-generated code requires the same level of understanding as a colleague’s code.

Over-Reliance: Skill Loss

A real risk, especially for junior and mid-level engineers. If AI always writes the implementation, the developer stops thinking at the code level.

Mitigation:

  • Regular code katas without AI
  • Architecture reviews where the human explains the decisions, not AI
  • Rotation: “no AI” periods for critical modules

Security Concerns

AI generates code with vulnerabilities:

  • SQL injection (if an ORM/parameterization isn’t used)
  • Hardcoded secrets (AI “invents” credentials)
  • Insecure defaults (disabled validation, CORS *)
  • Dependency confusion (nonexistent packages in imports)

Mitigation: SAST in CI/CD, npm audit in pre-commit, security-focused rules in the rules file, manual security review for auth/payment/data modules.

Managing Cost

AI tools cost money: models are billed by token, and a large context hits the budget.

Practice: monitor spending through the provider’s dashboard. Average budget — $100–250 per developer per month with active use. Savings from context engineering: fewer tokens in context = lower cost per request.

How to Get Started

Minimum Setup (Day 1)

  1. A rules file. Create CLAUDE.md (or .cursorrules / .cursor/rules/*.mdc for Cursor) with basic information: stack, build commands, 5–10 key project rules.
# CLAUDE.md
## Commands
npm run dev / npm test / npm run build

## Stack
TypeScript, React, Drizzle, PostgreSQL

## Rules
- Named exports only
- Tests next to source files (*.test.ts)
- No console.log in committed code
- Error handling: Result<T, E>, never throw in services
- All API inputs validated with Zod
  1. Pre-commit hooks. Set up in 10 minutes:
npx husky init
npm install -D lint-staged

# .husky/pre-commit
npx lint-staged
  1. Tests. Make sure the test framework is set up and one basic test passes. AI will generate tests — the infrastructure needs to be ready.

Progressive Buildout (Weeks 2–8)

Week 2: Expand the rules file. After every AI session where you had to make corrections, add a rule.

Week 3: Add project-specific eslint rules. import/no-default-export, no-restricted-imports, architectural boundaries.

Week 4: Try subagents (Claude Code) or the Agents Window (Cursor) for tasks that touch multiple files.

Weeks 5–6: Set up CI/CD with a full test run, coverage check, lint. Automate what you used to check manually.

Weeks 7–8: Skills/commands for repetitive operations: /review, /test, /refactor. MCP servers for integrations (GitHub, database).

Team Checklist

  • Rules file (CLAUDE.md / .cursorrules) in the repository
  • Pre-commit hooks: lint + format + type-check
  • Test infrastructure: framework set up, basic tests pass
  • Code review process updated: checklist for AI-generated code
  • Onboarding document: how to work with AI on this project
  • Metrics: velocity, defect rate, AI cost — baselines recorded
  • Rules review: weekly update to the rules file based on experience
  • Security: SAST in CI/CD, rules in the rules file for auth/data modules
  • Budget: spending limits on AI tools set and monitored

Vibe coding is an evolution of the engineering process, not a revolution. The models are good enough. The tools have matured. The enforcement infrastructure exists. All that’s left is to integrate it.

Engineers who treat AI as a contractor with clear rules get acceleration. Those who expect magic from AI or drop control get technical debt.

CLAUDE.md. Pre-commit hooks. Tests. Start there. The rest follows.

Frequently Asked Questions

What is vibe coding for engineers?
Vibe coding for engineers is a systematic approach to AI-assisted development where code is generated by AI within strict rules: CLAUDE.md / .cursorrules define the architecture, pre-commit hooks block low-quality code, and tests verify the result. It's a full engineering workflow, not just 'describe it and get it.'
How does vibe coding differ from regular AI coding?
Regular AI coding is one-off requests to a model ('write me a function'). Vibe coding is a system: rules files set the project context, agents decompose tasks, and enforcement (hooks, linters, tests) guarantees quality. The difference is like manual assembly versus an assembly line.
How do you introduce vibe coding to a team?
Start with three steps: 1) create a CLAUDE.md / .cursorrules file with project rules and commit it to the repository, 2) set up pre-commit hooks (lint + format + type-check), 3) add an AI-generated code checklist to your code review process. Expand gradually from there: agents, skills, CI/CD integration.
What tools do you need for vibe coding?
Minimum setup: an AI assistant (Claude Code, Cursor, Devin Desktop, or OpenAI Codex), a rules file (CLAUDE.md / .cursorrules), pre-commit hooks (husky + lint-staged), and a test framework. Advanced setup: MCP servers, subagents, CI/CD with AI checks, shared team rules, Bugbot/Codex Security for AI review.