DEV Community

Yigit Konur
Yigit Konur

Posted on

Complete Guide: How to Set AI Coding Rules for Multiple IDEs (Cursor & Windsurf & Claude Code & Gemini CLI & Cline & Zed+5 more)

A comprehensive, production-ready reference for configuring AI assistants across Cursor, Windsurf, Claude Code, Aider, Continue.dev, Cline, Roo-Cline, Zed, GitHub Copilot, and JetBrains AI Assistant


I. Introduction & Strategic Overview

1.1 Understanding the AI Coding Rules Landscape

The AI coding assistant ecosystem has matured rapidly between 2023-2025, converging on a critical insight: generic AI assistants produce generic code. Project-level instruction files transform general-purpose language models into specialized coding partners that understand your architecture, enforce your standards, and speak your team's technical dialect.

The Modern Reality (2025):

  • ~80% of agentic AI coding tools now support project-level instruction files
  • Markdown has emerged as the universal format (60% adoption) for natural language instructions
  • YAML/JSON handle structured configuration (25%) for model settings, tool permissions, and metadata
  • Cross-tool compatibility is now expected—developers frequently use 2-3 tools simultaneously

What Changed:

Era Configuration Approach Tools
2021-2022 No project-level config; global settings only Early GitHub Copilot
2023 Single-file Markdown rules emerge Cursor .cursorrules, early adopters
2024 Multi-file systems, YAML metadata, tool interop Windsurf Wave 8, Continue.dev, Aider
2025 Standardization around AGENTS.md, hierarchical rules, mode-based systems Roo-Cline modes, GitHub Copilot catches up

1.2 Why Project-Level Rules Matter

Quantified Benefits from Production Use:

Metric Without Rules With Well-Designed Rules Source
Onboarding Time 2-4 weeks 3-5 days Builder.io case study, 2025
Code Review Cycles 3-4 iterations 1-2 iterations Cursor community reports
AI Suggestion Acceptance 30-40% 70-90% Windsurf Zoominfo deployment
Standards Compliance 60-70% 90-95% Trigger.dev blog analysis
Debugging Time (AI-generated) 40% longer On par with human code DataCamp research

Real-World Impact:

Example 1: Fast-Growing Startup (15 engineers)

  • Before: Each developer explained project context in every AI chat session
  • After: Shared .cursorrules with tech stack, architecture, and anti-patterns
  • Result: 40% reduction in "where does X go?" questions, 25% faster PR merges

Example 2: Enterprise Fintech (200+ engineers)

  • Before: Inconsistent code generation across teams, security violations in AI suggestions
  • After: Organization-level Windsurf rules + project-specific overrides
  • Result: 90% reduction in security policy violations, standardized error handling

Example 3: Open Source Maintainer

  • Before: Contributors submitted code that didn't match project conventions
  • After: CLAUDE.md with explicit patterns and anti-patterns
  • Result: 60% fewer "please update to match our style" review comments

1.3 The Portability Challenge

The Multi-Tool Reality:

Modern development teams don't use a single AI assistant. A typical 10-person team might have:

  • 3 developers using Cursor (prefer Composer multi-file edits)
  • 2 developers using Windsurf (prefer Cascade's deep reasoning)
  • 2 developers using VS Code with Cline/Continue.dev (prefer open-source)
  • 2 developers using JetBrains IDEs with AI Assistant (Java/Kotlin focus)
  • 1 developer using Claude Code CLI (terminal-centric workflow)

The Challenge:

Without a portability strategy, you maintain 5 different rule files that drift out of sync, leading to:

  • ❌ Inconsistent AI behavior across team members
  • ❌ Wasted effort maintaining duplicate documentation
  • ❌ New hires confused by contradictory instructions
  • ❌ Technical debt in configuration management

The Solution (Detailed in Section V):

A Single Source of Truth (SSOT) architecture where one canonical instruction file (typically AGENTS.md or AI_RULES.md) is distributed to tool-specific locations through symlinks or build scripts.


II. Universal Principles Across All Tools

These principles apply regardless of which tool you use. They're grounded in how Large Language Models process context windows.

2.1 The Context Density Principle

The Physics of AI Context:

Every AI assistant has a context window (typically 64k-200k tokens). Your instruction file competes for space with:

  • Your actual code
  • Conversation history
  • Tool outputs and error messages
  • Retrieved documentation

Dense information wins. Prose-heavy instructions waste tokens on connecting words that don't change AI behavior.

❌ Low-Density (Bad):

We generally try to keep our components relatively small whenever it's 
reasonably possible to do so, because we've found through experience that 
smaller components tend to be easier to maintain and test. We'd appreciate 
it if you could try to follow this principle when you're generating code 
for our project.
Enter fullscreen mode Exit fullscreen mode

Token count: ~52 tokens
Actionable information: "Keep components small"

✅ High-Density (Good):

## Component Size Rules

ALWAYS break components > 200 lines into smaller units.
NEVER create single-file components with multiple responsibilities.

Example split:
- UserProfile.tsx (150 lines) → 
  - UserProfile.tsx (50 lines, layout)
  - UserAvatar.tsx (30 lines)
  - UserBio.tsx (40 lines)
  - UserStats.tsx (30 lines)
Enter fullscreen mode Exit fullscreen mode

Token count: ~48 tokens
Actionable information: Specific threshold (200 lines), concrete example, clear directives

High-Density Patterns:

Pattern Description Example
Binary Constraints Use ALWAYS/NEVER ALWAYS validate inputs. NEVER trust user data.
Numbered Rules Sequential, scannable 1. Type hints required 2. Max 50 lines/function 3. Docstrings mandatory
Code > Prose Show don't tell Include 3-5 line code examples vs paragraphs of description
Hierarchical Headers Markdown H2/H3 for scanning Use ## for categories, ### for specifics
Tables for Mappings Structured data File patterns → conventions, Error types → handling

2.2 Tech Stack Declaration Best Practices

Why It Matters:

When you tell an AI "we use React," it must choose between:

  • React 16 (class components, lifecycle methods)
  • React 17 (functional components emerging)
  • React 18 (concurrent rendering)
  • React 19 (Server Components, new use hook)

Without version specificity, the AI defaults to its training data average—likely outdated patterns.

Universal Tech Stack Template:

# Technology Stack

## Language & Runtime
- **Language**: TypeScript 5.4 (strict mode enabled)
- **Runtime**: Node.js 20.11 LTS
- **Package Manager**: pnpm 9.0 (NOT npm/yarn)

## Frontend Framework
- **Core**: React 19.0
- **Meta-Framework**: Next.js 15 (App Router, NOT Pages Router)
- **Styling**: Tailwind CSS 4.0
- **Components**: Radix UI primitives + shadcn/ui

## State Management
- **Server State**: TanStack Query v5 (React Query)
- **Client State**: Zustand 4.5 (NOT Redux)
- **Form State**: React Hook Form 7.5 + Zod 3.23

## Backend Framework
- **API Framework**: tRPC 11 for type-safe APIs
- **Database**: PostgreSQL 16
- **ORM**: Drizzle ORM 0.35 (NOT Prisma)

## Testing
- **Unit/Integration**: Vitest 2.0 (NOT Jest)
- **E2E**: Playwright 1.45
- **Component**: Testing Library (React)

## Build & Deploy
- **Bundler**: Turbopack (Next.js built-in)
- **Monorepo**: Turborepo 2.0
- **Hosting**: Vercel (production), Railway (staging)
- **CI/CD**: GitHub Actions
Enter fullscreen mode Exit fullscreen mode

Why Each Detail Matters:

Specification Why Critical What AI Does Differently
pnpm NOT npm Different lockfile format, workspace protocol Uses pnpm install vs npm install, references workspace:* deps
App Router NOT Pages Completely different file structure, data fetching Server Components by default, uses app/ not pages/
Zustand NOT Redux Different API, no boilerplate Creates clean stores vs action/reducer/dispatch patterns
Vitest NOT Jest Different config, faster, ESM-first Uses vitest.config.ts, native ESM imports
Drizzle NOT Prisma SQL-centric vs abstraction-heavy Writes migrations as SQL, uses drizzle-kit commands

2.3 Positive vs. Negative Constraints

The LLM "NOT" Problem:

Language models trained on vast amounts of code have deeply ingrained patterns. A simple "don't do X" fights against thousands of training examples. Negative constraints work best when paired with positive alternatives that provide a clear path forward.

Effectiveness Hierarchy (from research):

Constraint Type Adherence Rate Example
Negative only ~40-50% "Don't use any type"
Negative + reason ~60-70% "Don't use any (breaks type safety)"
Negative + alternative ~85-90% "Don't use any. Use unknown then narrow with type guards"
Negative + alternative + example ~95%+ Full pattern below

✅ Maximum Effectiveness Pattern:

## Type Safety Rules

### ❌ NEVER: The `any` Escape Hatch

Enter fullscreen mode Exit fullscreen mode


typescript
// FORBIDDEN - Breaks type safety completely
function processData(data: any) {
return data.someProperty; // No autocomplete, no errors
}


**Why it's forbidden:** Disables TypeScript's entire value proposition. One `any` can cascade type unsafety through your codebase.

### ✅ DO: Use `unknown` + Type Guards

Enter fullscreen mode Exit fullscreen mode


typescript
// CORRECT - Maintains type safety
function processData(data: unknown) {
// Type guard narrows unknown → specific type
if (isValidDataShape(data)) {
return data.someProperty; // Now type-safe!
}
throw new AppError('Invalid data shape', 400);
}

// Type guard helper
function isValidDataShape(data: unknown): data is DataShape {
return (
typeof data === 'object' &&
data !== null &&
'someProperty' in data
);
}


**When you need flexibility:**
- Use `unknown` for data from external APIs, user input, or parsed JSON
- Use generics for reusable functions: `function process<T>(data: T): T`
- Use branded types for validated data: `type ValidatedData = Data & { __validated: true }`
Enter fullscreen mode Exit fullscreen mode

Pairing Pattern Structure:

  1. ❌ NEVER section: Show the anti-pattern with code
  2. Why it's forbidden: Explain consequences (security, performance, maintainability)
  3. ✅ DO section: Show the correct pattern with full example
  4. When you need flexibility: Cover edge cases and alternatives

2.4 The Structure Hierarchy Standard

The 7-Section Framework:

Based on analysis of 100+ production rule files from Cursor (awesome-cursorrules), Anthropic's Claude Code documentation, and enterprise deployments, this structure consistently produces the highest AI adherence:

# [Project Name] - [One-line Description]

## 1. PROJECT OVERVIEW (30-50 words)
Brief context about what this project does and its primary goal.

## 2. TECHNOLOGY STACK (Exhaustive list with versions)
See Section 2.2 template above.

## 3. ARCHITECTURE & STRUCTURE (File tree + explanations)
Enter fullscreen mode Exit fullscreen mode

src/
├── app/ # Next.js routes (App Router)
├── components/ # Reusable React components
│ ├── ui/ # shadcn/ui primitives
│ └── features/ # Feature-specific components
├── lib/ # Utilities, helpers, business logic
│ ├── api/ # tRPC routers and procedures
│ ├── db/ # Drizzle schema and queries
│ └── utils/ # Pure functions, formatters
└── tests/ # Test files mirror src/ structure


Key architectural decisions:
- **Feature-first organization**: Group by feature domain, not technical type
- **Server Components by default**: Only add 'use client' when needed
- **Colocation**: Keep component, styles, tests together

## 4. CODING STANDARDS (With examples and anti-patterns)
See Section 2.3 for effective pattern structure.

## 5. TESTING REQUIREMENTS (Commands, coverage, approaches)
- **Unit**: 80% coverage minimum, `pnpm test`
- **Integration**: API endpoints with MSW, `pnpm test:integration`
- **E2E**: Critical paths only, `pnpm test:e2e`

## 6. COMMON PITFALLS & KNOWN ISSUES (Save time debugging)
- **Pitfall**: Mixing Server/Client components incorrectly
  - **Symptom**: "useState can only be used in Client Components"
  - **Fix**: Add 'use client' at top of file, or lift state up

## 7. IMPORTANT NOTES & CONSTRAINTS
- API rate limit: 100 req/min per IP
- JWT expires: 24h (refresh token: 30d)
- All routes: `/api/v1/*` prefix
Enter fullscreen mode Exit fullscreen mode

Why This Order:

Section Why First? What AI Gains
Overview Instant orientation Understands project domain before seeing details
Stack Prunes possibility space Knows which libraries/patterns are relevant
Architecture File system mental model Can reason about "where should this code go?"
Standards How to write code Applies patterns during generation
Testing Quality gates Knows what tests to write, when
Pitfalls Learn from experience Avoids known failure modes
Notes Critical constraints Respects security, API, business rules

2.5 Anti-Patterns to Avoid Universally

The "Encyclopedia" Anti-Pattern:

Symptom: Rules file is 5,000+ words, comprehensive documentation of every possible coding scenario.

Why it fails:

  • Consumes 15-20% of context window
  • AI spends tokens retrieving irrelevant sections
  • High-priority rules get buried in noise
  • Maintenance becomes overwhelming

Real example: A team's .cursorrules included:

  • Complete React documentation excerpts (1,200 words)
  • Full ESLint rule explanations (800 words)
  • Git workflow with branching strategy diagrams (600 words)
  • Code review checklist (400 words)
  • Team meeting notes (300 words)

Result: AI followed ~30% of actual project-specific rules because they were lost in generic content.

Fix: Keep project-specific rules under 500 lines. Link to external docs:

## Additional Resources

For comprehensive React patterns, see: @docs/react-patterns.md
For ESLint rules, run: `npm run lint -- --print-config`
For Git workflow, see: CONTRIBUTING.md
Enter fullscreen mode Exit fullscreen mode

The "Be Clean" Ambiguity Anti-Pattern:

Symptom: Rules use vague subjective terms without concrete definitions.

- Write clean code
- Keep functions simple
- Use modern JavaScript
- Be consistent
- Make it performant
Enter fullscreen mode Exit fullscreen mode

Why it fails:

  • "Clean" means different things to different people (and LLMs)
  • "Simple" without threshold is meaningless
  • "Modern" changes yearly and varies by training data cutoff
  • "Consistent" with what baseline?

Fix: Replace every subjective term with measurable criteria:

## Code Quality Standards

### Function Complexity
- **Max lines per function**: 50 (enforced by ESLint)
- **Max parameters**: 4 (use options object if more needed)
- **Max cyclomatic complexity**: 10 (ESLint complexity rule)

### Modern JavaScript (ES2022+)
- ✅ DO: `async/await`, optional chaining `?.`, nullish coalescing `??`
- ❌ DON'T: `.then()` chains, `_.get()` (use `?.`), `|| ` for defaults (use `??`)

### Consistency
Follow Prettier config (committed in `.prettierrc.json`):
- 2-space indentation
- Single quotes
- No semicolons
- Trailing commas
Enter fullscreen mode Exit fullscreen mode

The "Conflicting Roles" Anti-Pattern:

Symptom: Rules describe the AI with contradictory personas.

You are a senior principal engineer with 20 years of experience.
Explain everything in detail suitable for junior developers.
Move fast and break things.
Ensure enterprise-grade stability and reliability.
Enter fullscreen mode Exit fullscreen mode

Why it fails:

  • Creates cognitive dissonance in the model's generation process
  • "Senior engineer" suggests terseness and assumptions
  • "Junior audience" suggests verbosity and hand-holding
  • "Move fast" conflicts with "enterprise-grade stability"

Fix: Choose ONE primary persona aligned with your actual needs:

# AI Role Definition

You are a senior software engineer on a fast-paced startup team. Your priorities:

1. **Velocity**: Ship working features quickly
2. **Pragmatism**: Choose simple solutions over clever ones
3. **Context**: Assume the reader is an experienced developer
4. **Standards**: Follow established patterns, don't reinvent

When there's tension between speed and perfection, bias toward speed with inline TODOs for future improvements.
Enter fullscreen mode Exit fullscreen mode

The "Dead Link" Anti-Pattern:

Symptom: Rules reference external URLs expecting AI to browse.

Follow our API conventions at: https://docs.company.com/api-design
See authentication flow: https://wiki.company.com/auth
Database schema: https://dbdiagram.io/d/project-schema
Enter fullscreen mode Exit fullscreen mode

Why it fails:

  • Most AI coding assistants cannot reliably browse URLs during code generation
  • Even those with browsing capability (Claude Code, some Cursor modes) have latency/reliability issues
  • Broken links fail silently—AI just skips the instruction

Fix: Inline critical information, use local file references:

## API Conventions (from docs/api-design.md)

Every endpoint returns this structure:
Enter fullscreen mode Exit fullscreen mode


json
{
"success": boolean,
"data": T | null,
"error": {
"code": string,
"message": string
} | null
}


## Authentication Flow

See @docs/auth-flow.md for complete flow, key points:
- JWT in `Authorization: Bearer <token>` header
- Refresh tokens: POST /api/auth/refresh
- Token expiry: 15 minutes (access), 7 days (refresh)

## Database Schema

See @prisma/schema.prisma for full schema. Core entities:
- Users → Profiles (1:1)
- Users → Posts (1:N)
- Posts → Comments (1:N)
Enter fullscreen mode Exit fullscreen mode

Tool-specific file reference syntax:

  • Cursor: [filename](mdc:path/to/file)
  • Continue.dev: @path/to/file
  • Claude Code: @docs/filename.md
  • Windsurf: Direct markdown includes or @import syntax
  • Aider: Load via read: [path/to/file] in .aider.conf.yml

III. Format Comparison Matrix

Understanding when to use Markdown vs YAML vs JSON vs TOML is critical for choosing the right tool and configuration strategy.

3.1 Markdown vs YAML vs JSON vs TOML

The Format Decision Tree:

Do you need machine-parseable structured data (model config, tool permissions)?
├─ YES → Use YAML, JSON, or TOML
│   ├─ Need comments & human readability? → YAML
│   ├─ Need strict validation & tooling? → JSON
│   └─ Rust/systems project? → TOML
└─ NO → Are you writing natural language instructions?
    └─ YES → Use Markdown
Enter fullscreen mode Exit fullscreen mode

Comprehensive Comparison:

Aspect Markdown YAML JSON TOML
Primary Use Natural language instructions Configuration with hierarchy Strict config & APIs Rust ecosystem config
Human Readability ⭐⭐⭐⭐⭐ Excellent ⭐⭐⭐⭐ Very Good ⭐⭐⭐ Good ⭐⭐⭐⭐ Very Good
AI Processing ⭐⭐⭐⭐⭐ Native ⭐⭐⭐ Parsed to text ⭐⭐⭐ Parsed to text ⭐⭐⭐ Parsed to text
Validation ❌ None ⚠️ Schema possible ✅ JSON Schema ⚠️ Limited
Comments ✅ Native # comment ❌ Not standard # comment
Multi-line Strings ✅ Native ✅ ` or >` ❌ Escaped \n
Nesting ⚠️ Headers only ✅ Indentation ✅ Objects ⚠️ Tables
Version Control ⭐⭐⭐⭐⭐ Excellent diffs ⭐⭐⭐⭐ Good diffs ⭐⭐⭐ Acceptable ⭐⭐⭐⭐ Good diffs
Tool Support 🛠️ All AI tools 🛠️ Continue.dev, Roo-Cline, Aider, Windsurf 🛠️ Continue.dev, Roo-Cline (legacy) 🛠️ Zed (settings only)
Best For Instructions, examples, prose Hierarchical config, metadata API contracts, strict validation Rust projects, simple configs

Detailed Format Analysis:

Markdown: The Universal Instruction Format

Strengths:

# Why Markdown Wins for Instructions

## Native AI Processing
LLMs are trained on markdown documentation. Headers, lists, and code blocks
are "native" structures that don't require parsing.

## Flexible Structure
- Hierarchical headers (H1-H6)
- Ordered and unordered lists
- Tables for structured data
- Code blocks with syntax highlighting
- Inline code for `commands`
- Emphasis with **bold** and *italic*

## Example-Rich
Enter fullscreen mode Exit fullscreen mode


typescript
// Show actual code examples directly
interface User {
id: string;
name: string;
}


## Git-Friendly
Semantic line breaks make diffs clean:
- Each sentence on its own line
- Changes are isolated
- Merge conflicts rare
Enter fullscreen mode Exit fullscreen mode

Weaknesses:

  • No schema validation (typos not caught)
  • No type checking for values
  • Nesting limited to headers
  • Can't enforce structure programmatically

When to Use:

  • Project context and overview
  • Coding standards and conventions
  • Architecture documentation
  • Examples and anti-patterns
  • Testing strategies
  • Any natural language instruction

Tools Using Markdown:

  • Cursor (.cursor/rules/*.mdc body)
  • Windsurf (.windsurfrules body)
  • Claude Code (CLAUDE.md)
  • Cline (.clinerules)
  • Zed (.rules)
  • GitHub Copilot (.github/copilot-instructions.md)
  • JetBrains (.aiassistant/rules/*.md)

YAML: The Readable Configuration Format

Strengths:

# YAML Example - Continue.dev config.yaml

# Comments are first-class citizens
models:
  - name: Claude 3.5 Sonnet
    provider: anthropic
    model: claude-3-5-sonnet-20241022
    roles: [chat, edit, apply]

    # Multi-line strings with block scalars
    chatOptions:
      baseSystemMessage: |
        You are an expert TypeScript engineer.
        Focus on type safety and performance.

    # Nested configuration
    defaultCompletionOptions:
      temperature: 0.7
      maxTokens: 4000

    # Lists are clean
    capabilities:
      - tool_use
      - image_input

# Anchors and aliases for reuse
base_settings: &base
  temperature: 0.5
  maxTokens: 2000

gpt4_model:
  <<: *base  # Inherit base settings
  model: gpt-4o
Enter fullscreen mode Exit fullscreen mode

Weaknesses:

  • Indentation-sensitive (tabs vs spaces errors)
  • Subtle syntax gotchas (: in strings, yes/no boolean coercion)
  • Ambiguous anchor/alias behavior
  • No schema enforcement (unless using external validator)

Common YAML Pitfalls:

# ❌ WRONG - Boolean coercion gotcha
country: NO  # Parsed as false, not "NO"

# ✅ CORRECT - Quote strings
country: "NO"

# ❌ WRONG - Colon in unquoted string
message: Error: File not found  # Syntax error

# ✅ CORRECT - Quote strings with special chars
message: "Error: File not found"

# ❌ WRONG - Tab indentation (invisible error)
rules:
→   - First rule  # Tab character breaks parsing

# ✅ CORRECT - Space indentation
rules:
  - First rule  # Spaces work
Enter fullscreen mode Exit fullscreen mode

When to Use:

  • Hierarchical configuration (models, tools, contexts)
  • Settings with nested structure
  • Configuration requiring comments
  • Multi-line text blocks
  • Reusable config chunks (anchors)

Tools Using YAML:

  • Aider (.aider.conf.yml)
  • Continue.dev (config.yaml)
  • Roo-Cline (.roomodes preferred over JSON)
  • Windsurf (YAML frontmatter in .windsurfrules)

JSON: The Strict Configuration Format

Strengths:

{
  "// comments": "Workaround for lack of native comments",

  "models": [{
    "name": "GPT-4o",
    "provider": "openai",
    "model": "gpt-4o",
    "apiKey": "${OPENAI_API_KEY}",
    "roles": ["chat", "edit"],

    "chatOptions": {
      "baseSystemMessage": "You are a helpful coding assistant."
    }
  }],

  "rules": [
    "Use TypeScript strict mode",
    "Prefer functional components"
  ],

  "context": [
    {
      "provider": "code"
    },
    {
      "provider": "codebase",
      "params": {
        "nRetrieve": 30,
        "nFinal": 5
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Strengths:

  • JSON Schema validation: Catch errors before runtime
  • Universal parser support: Every language has JSON libraries
  • Strict syntax: No ambiguity like YAML booleans
  • IDE autocomplete: With JSON Schema, get IntelliSense

Weaknesses:

  • No native comments (use workarounds like "_comment" keys)
  • Verbose: All keys quoted, no multi-line strings
  • No trailing commas: Last item can't have comma (JSON5 fixes this)
  • Escaping hell: Strings need \", \\, \n etc.

JSON vs JSON5 (VS Code supports JSON5 in settings):

{
  // Native comments supported
  models: [  // Unquoted keys allowed
    {
      name: "GPT-4o",  // Trailing comma OK
    },
  ],

  rules: [
    "Use TypeScript \
     strict mode",  // Multi-line strings
  ],
}
Enter fullscreen mode Exit fullscreen mode

When to Use:

  • API configuration (strict schemas)
  • Generated config (tooling creates it)
  • Cross-platform compatibility (guaranteed parsing)
  • When JSON Schema validation is critical

Tools Using JSON:

  • Continue.dev (legacy config.json, deprecated)
  • Roo-Cline (.roomodes supports JSON)
  • VS Code settings (JSON with comments)

TOML: The Rust Ecosystem Format

Strengths:

# TOML Example - Hypothetical Zed config (actual Zed uses JSON)

# Clear, unambiguous key-value pairs
version = "1.0"
schema = "v1"

# Tables for grouping
[models.gpt4]
name = "GPT-4o"
provider = "openai"
model = "gpt-4o"
roles = ["chat", "edit"]

# Nested tables
[models.gpt4.chatOptions]
baseSystemMessage = """
You are an expert TypeScript engineer.
Focus on type safety and performance.
"""  # Multi-line strings with """

# Arrays of tables
[[rules]]
name = "typescript_strict"
globs = ["**/*.ts", "**/*.tsx"]
prompt = """
Use TypeScript strict mode.
All functions need explicit return types.
"""

[[rules]]
name = "react_hooks"
globs = ["**/*.tsx"]
prompt = "Prefer functional components with hooks."
Enter fullscreen mode Exit fullscreen mode

Strengths:

  • Unambiguous syntax: No YAML's boolean coercion issues
  • Clear nesting: Tables ([section]) are explicit
  • Multi-line strings: Native """ support
  • Strong typing: Dates, times, integers, floats are distinct

Weaknesses:

  • Limited adoption outside Rust: Primarily Cargo, config files
  • Verbose for deep nesting: Requires explicit table paths
  • Tooling: Less IDE support than YAML/JSON

When to Use:

  • Rust/Cargo projects (natural fit)
  • Simple, flat configurations
  • When YAML indentation errors are problematic
  • Projects already using TOML elsewhere

Tools Using TOML:

  • ⚠️ Zed does NOT use TOML for AI rules (uses Markdown .rules)
  • Zed uses TOML for: extension.toml, language config.toml, .taplo.toml (linter)
  • Conceptually similar to what could be used for structured rule metadata

3.2 When to Use Each Format

Decision Matrix:

Your Need Recommended Format Rationale
Natural language instructions Markdown AI processes natively, human-readable, example-rich
Project context & architecture Markdown Documentation-style content, flexible structure
Model configuration YAML or JSON Hierarchical settings, schema validation possible
Tool permissions & restrictions YAML or JSON Structured rules, programmatic validation
Cross-tool compatibility Markdown (AGENTS.md) Universal format, all tools read markdown
Strict validation required JSON + JSON Schema Type-checked, IDE autocomplete
Team readability priority YAML Comments, clean diffs, readable nesting
API/generated config JSON Machine-generated, strict parsing
Rust ecosystem TOML Native cargo integration

Hybrid Approach (Most Common in Practice):

Modern tools use structured format (YAML/JSON) for metadata + Markdown for instructions:

Example: Continue.dev

# config.yaml (structured settings)
models:
  - name: Claude 3.5
    provider: anthropic
    model: claude-3-5-sonnet-20241022
    roles: [chat, edit]

# Markdown rules loaded separately
rules:
  - uses: ./blocks/typescript-standards.md
Enter fullscreen mode Exit fullscreen mode

Example: Roo-Cline

# .roomodes (YAML for mode structure)
customModes:
  - slug: typescript-expert
    name: TypeScript Expert
    groups:
      - read
      - [edit, { fileRegex: '\\.tsx?$' }]

    # Markdown content in YAML string
    customInstructions: |
      # TypeScript Standards

      - Use strict mode
      - Explicit return types
      - Zod for validation
Enter fullscreen mode Exit fullscreen mode

Example: Cursor

---
# YAML frontmatter for metadata
description: "TypeScript coding standards"
globs: ["**/*.ts", "**/*.tsx"]
alwaysApply: false
---

# Markdown body for actual instructions

## Type Safety Rules
[Natural language instructions here...]
Enter fullscreen mode Exit fullscreen mode

IV. Tool-Specific Deep Dives

4.1 Cursor Configuration

Cursor has evolved to become the market leader in AI-first IDEs, and its configuration system reflects sophisticated design choices based on real-world usage at scale.

4.1.1 Modern .cursor/rules/*.mdc System

Overview:

  • Format: .mdc (Markdown Cursor) = YAML frontmatter + Markdown body
  • Location: .cursor/rules/ directory in project root
  • Status: Official, recommended approach since v0.40 (2024)
  • Auto-load: Rules are automatically applied based on frontmatter metadata

Complete MDC File Structure:

---
description: "TypeScript and React coding standards for frontend"
globs:
  - "src/**/*.{ts,tsx}"
  - "app/**/*.{ts,tsx}"
alwaysApply: false
---

# Frontend TypeScript Standards

## Context
This project uses Next.js 15 App Router with TypeScript strict mode.
Server Components are the default; only use Client Components when necessary.

## Component Rules

### Structure
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ Preferred: Named export, typed props
interface UserCardProps {
user: User;
onEdit: (id: string) => void;
}

export function UserCard({ user, onEdit }: UserCardProps) {
return

{user.name};
}

// ❌ Avoid: Default export, inline types
export default function UserCard({ user, onEdit }: {
user: any;
onEdit: Function;
}) {
return

{user.name};
}

### Size Limits
- **Max component length**: 200 lines
- **If exceeded**: Split into smaller components
- **Composition over props drilling**: Use composition pattern

## State Management

| Use Case | Solution | Example |
|----------|----------|---------|
| Server data | TanStack Query | `useQuery('users', fetchUsers)` |
| Client state | useState | `const [open, setOpen] = useState(false)` |
| Global client | Zustand | `const user = useUserStore(s => s.user)` |
| URL state | useSearchParams | `const [search] = useSearchParams()` |

## Always Include
Enter fullscreen mode Exit fullscreen mode


typescript
// Type all props explicitly
interface Props {
// Document complex props
children: ReactNode;
}

// Type event handlers
onClick: (event: MouseEvent) => void;

// Async handlers need error handling
async function handleSubmit() {
try {
await saveData();
} catch (error) {
if (error instanceof ApiError) {
toast.error(error.message);
}
}
}

Enter fullscreen mode Exit fullscreen mode

YAML Frontmatter Fields (Complete Reference):

Field Type Required Purpose Example
description string Yes Human-readable summary for agent-requested rules "Apply when working with React components"
globs string[] No File patterns for auto-attachment (gitignore syntax) ["src/**/*.ts", "!**/*.test.ts"]
alwaysApply boolean No If true, applies to every request regardless of context true
tags string[] No Categorization (not widely used yet) ["frontend", "testing"]
priority number No When multiple rules match, higher priority wins 10

Rule Type Inference Logic:

Cursor infers the rule type from frontmatter combinations:

Frontmatter Inferred Type Behavior
alwaysApply: true Always Included in every Cursor request
globs: [...] Auto Attached Applied when editing matching files
description: "..." (no globs) Agent Requested AI decides based on description
No description, no globs Manual Only used when explicitly @mentioned

Example: Complete Multi-File Setup

my-project/
├── .cursor/
│   └── rules/
│       ├── index.mdc                 # Always-apply project overview
│       ├── typescript-frontend.mdc   # Auto-attach to *.ts, *.tsx
│       ├── api-backend.mdc           # Auto-attach to api/**/*
│       ├── testing.mdc               # Manual invocation for test writing
│       └── security.mdc              # Agent-requested for security contexts
└── src/
Enter fullscreen mode Exit fullscreen mode

index.mdc (Always Applied):

---
description: "Project-wide standards and context"
alwaysApply: true
---

# Project Overview

**Stack**: Next.js 15, TypeScript, PostgreSQL, tRPC
**Architecture**: Monorepo with Turborepo
**Deployment**: Vercel (prod), Railway (staging)

## Universal Rules
- Use pnpm (NOT npm)
- Commits follow Conventional Commits
- All PRs require 1 approval
- Run `pnpm lint` before committing
Enter fullscreen mode Exit fullscreen mode

typescript-frontend.mdc (Auto-Attached):

---
description: "Frontend TypeScript and React standards"
globs:
  - "app/**/*.{ts,tsx}"
  - "components/**/*.{ts,tsx}"
---

# Frontend Standards
[See detailed example above]
Enter fullscreen mode Exit fullscreen mode

testing.mdc (Manual):

---
description: "Testing guidelines and patterns"
---

# Testing Standards

When writing tests, follow this structure:

## Unit Tests (Vitest)
Enter fullscreen mode Exit fullscreen mode


typescript
import { describe, it, expect } from 'vitest';

describe('calculateTotal', () => {
it('sums item prices', () => {
const items = [{ price: 10 }, { price: 20 }];
expect(calculateTotal(items)).toBe(30);
});

it('handles empty array', () => {
expect(calculateTotal([])).toBe(0);
});
});


## Component Tests (Testing Library)
Enter fullscreen mode Exit fullscreen mode


typescript
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

it('submits form on button click', async () => {
const onSubmit = vi.fn();
render();

await userEvent.type(screen.getByLabelText('Name'), 'John');
await userEvent.click(screen.getByRole('button', { name: 'Submit' }));

expect(onSubmit).toHaveBeenCalledWith({ name: 'John' });
});

Enter fullscreen mode Exit fullscreen mode

security.mdc (Agent-Requested):

---
description: "Apply when handling authentication, user data, or API keys"
---

# Security Standards

## Authentication
- JWTs in HttpOnly cookies (NEVER localStorage)
- Refresh token rotation on use
- CSRF protection on state-changing endpoints

## Data Validation
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ ALWAYS validate with Zod
import { z } from 'zod';

const UserSchema = z.object({
email: z.string().email(),
password: z.string().min(12),
});

// Validate before using
const user = UserSchema.parse(untrustedData);


## Secrets Management
- ❌ NEVER hardcode: `const apiKey = "sk_live_..."`
- ✅ Use environment: `process.env.API_KEY`
- ✅ Validate env vars: Use `@t3-oss/env-nextjs`
Enter fullscreen mode Exit fullscreen mode

4.1.2 File References with mdc: Scheme

Cursor supports inline file references to inject additional context:

---
description: "API development standards"
globs: ["src/api/**/*"]
---

# API Standards

For complete authentication flow, see: [auth-flow.ts](mdc:src/api/auth/auth-flow.ts)

For error handling patterns, see: [errors.ts](mdc:src/lib/errors.ts)

## Key Patterns

Follow the pattern in [user-router.ts](mdc:src/api/routers/user-router.ts):
- Input validation with Zod
- Error handling with custom AppError
- Consistent response format
Enter fullscreen mode Exit fullscreen mode

How mdc: Links Work:

  1. Cursor reads the referenced file
  2. Includes its content in the rule's context
  3. AI can reference specific patterns from those files
  4. Useful for pointing to canonical implementations

Best Practices:

  • ✅ Reference small, focused files (< 200 lines)
  • ✅ Use for showing implementation patterns
  • ✅ Point to configuration files (schema, types)
  • ❌ Don't reference large files (wastes tokens)
  • ❌ Don't chain many references (context overflow)

4.1.3 Advanced Patterns

Pattern 1: Per-Language Rules

.cursor/rules/
├── index.mdc                # Project overview (always)
├── typescript.mdc           # globs: ["**/*.ts", "**/*.tsx"]
├── python.mdc               # globs: ["**/*.py"]
├── sql.mdc                  # globs: ["**/*.sql"]
└── markdown.mdc             # globs: ["**/*.md"]
Enter fullscreen mode Exit fullscreen mode

Pattern 2: Feature-Based Rules

.cursor/rules/
├── index.mdc                # Core standards
├── auth-feature.mdc         # globs: ["src/features/auth/**/*"]
├── payments-feature.mdc     # globs: ["src/features/payments/**/*"]
└── admin-feature.mdc        # globs: ["src/features/admin/**/*"]
Enter fullscreen mode Exit fullscreen mode

Pattern 3: Role-Based Rules

.cursor/rules/
├── architect.mdc            # Agent-requested for system design
├── implementer.mdc          # Auto-attach for .ts files
├── tester.mdc               # Manual for test writing
└── reviewer.mdc             # Agent-requested for code review
Enter fullscreen mode Exit fullscreen mode

4.1.4 Production Examples & Templates

Complete Next.js 15 + TypeScript Template:

---
description: "Next.js 15 App Router with TypeScript and Tailwind"
alwaysApply: true
---

# Next.js 15 Full-Stack Project

## Tech Stack
- **Frontend**: Next.js 15 (App Router), React 19, TypeScript 5.4
- **Styling**: Tailwind CSS 4.0, shadcn/ui components
- **Backend**: tRPC 11, Drizzle ORM, PostgreSQL 16
- **Auth**: NextAuth.js v5 (Auth.js)
- **State**: TanStack Query, Zustand for global client state
- **Testing**: Vitest, Testing Library, Playwright

## Project Structure
Enter fullscreen mode Exit fullscreen mode

src/
├── app/ # Next.js routes
│ ├── (auth)/ # Auth group (login, register)
│ ├── (dashboard)/ # Protected dashboard
│ ├── api/ # API routes (minimal, prefer tRPC)
│ └── layout.tsx # Root layout
├── components/
│ ├── ui/ # shadcn/ui primitives
│ ├── forms/ # Reusable form components
│ └── layouts/ # Layout components
├── lib/
│ ├── api/ # tRPC routers
│ ├── db/ # Drizzle schema and queries
│ ├── auth/ # Auth utilities
│ └── utils/ # Helpers
└── types/ # Shared TypeScript types


## Server vs Client Components

### Default: Server Components
Enter fullscreen mode Exit fullscreen mode


tsx
// ✅ Server Component (default, no directive needed)
async function UserProfile({ userId }: { userId: string }) {
// Can fetch data directly
const user = await db.query.users.findFirst({
where: eq(users.id, userId)
});

return

{user.name};
}

### Only add 'use client' when:
1. Using React hooks (useState, useEffect, etc.)
2. Event handlers (onClick, onChange, etc.)
3. Browser APIs (window, localStorage, etc.)
4. Third-party libraries that use client features

Enter fullscreen mode Exit fullscreen mode


tsx
'use client';

import { useState } from 'react';

// ✅ Client Component (hooks require it)
function Counter() {
const [count, setCount] = useState(0);
return setCount(count + 1)}>{count};
}


## Data Fetching Patterns

| Pattern | Use Case | Example |
|---------|----------|---------|
| **Server Component** | Static/initial data | `const data = await fetchData()` |
| **tRPC Query** | Client-side fetching | `const { data } = trpc.users.list.useQuery()` |
| **Server Action** | Mutations | `async function updateUser(data: FormData)` |

## Type Safety

### Zod Schemas
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ Define schema once
import { z } from 'zod';

export const UserSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
age: z.number().min(18).optional(),
});

// Infer TypeScript type
export type User = z.infer;

// Use for validation
const user = UserSchema.parse(untrustedData);


### tRPC Procedures
Enter fullscreen mode Exit fullscreen mode


typescript
// src/lib/api/routers/user.ts
import { z } from 'zod';
import { createTRPCRouter, protectedProcedure } from '../trpc';

export const userRouter = createTRPCRouter({
list: protectedProcedure
.query(async ({ ctx }) => {
return await ctx.db.query.users.findMany();
}),

create: protectedProcedure
.input(UserSchema)
.mutation(async ({ ctx, input }) => {
return await ctx.db.insert(users).values(input);
}),
});


## Error Handling

### Client-Side
Enter fullscreen mode Exit fullscreen mode


typescript
'use client';

import { trpc } from '@/lib/trpc/client';
import { toast } from 'sonner';

function MyComponent() {
const mutation = trpc.users.create.useMutation({
onSuccess: () => {
toast.success('User created');
},
onError: (error) => {
// Error is fully typed
toast.error(error.message);
},
});

return mutation.mutate({ ... })}>Create;
}


### Server-Side
Enter fullscreen mode Exit fullscreen mode


typescript
import { TRPCError } from '@trpc/server';

export const userRouter = createTRPCRouter({
delete: protectedProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ ctx, input }) => {
const user = await ctx.db.query.users.findFirst({
where: eq(users.id, input.id)
});

  if (!user) {
    throw new TRPCError({
      code: 'NOT_FOUND',
      message: 'User not found',
    });
  }

  // Perform deletion...
}),
Enter fullscreen mode Exit fullscreen mode

});


## Testing Standards

### Unit Tests (Vitest)
Enter fullscreen mode Exit fullscreen mode


typescript
// src/lib/utils/format.test.ts
import { describe, it, expect } from 'vitest';
import { formatCurrency } from './format';

describe('formatCurrency', () => {
it('formats USD correctly', () => {
expect(formatCurrency(1234.56, 'USD')).toBe('$1,234.56');
});

it('handles zero', () => {
expect(formatCurrency(0, 'USD')).toBe('$0.00');
});
});


### Component Tests
Enter fullscreen mode Exit fullscreen mode


typescript
// src/components/UserCard.test.tsx
import { render, screen } from '@testing-library/react';
import { UserCard } from './UserCard';

it('displays user name', () => {
const user = { id: '1', name: 'John Doe', email: 'john@example.com' };
render();
expect(screen.getByText('John Doe')).toBeInTheDocument();
});


### E2E Tests (Playwright)
Enter fullscreen mode Exit fullscreen mode


typescript
// tests/e2e/auth.spec.ts
import { test, expect } from '@playwright/test';

test('user can sign in', async ({ page }) => {
await page.goto('/login');
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
});


## Common Commands
- `pnpm dev` - Start dev server (localhost:3000)
- `pnpm build` - Production build
- `pnpm lint` - Run ESLint
- `pnpm type-check` - TypeScript check
- `pnpm test` - Run Vitest unit tests
- `pnpm test:e2e` - Run Playwright E2E tests
- `pnpm db:push` - Push schema to database
- `pnpm db:studio` - Open Drizzle Studio

## Known Issues

### Hot Reload with tRPC
**Symptom**: tRPC client doesn't update after router changes
**Solution**: Restart dev server when adding/removing procedures

### Server Action Hydration
**Symptom**: "Text content did not match" errors
**Solution**: Ensure Server Actions are truly async and await all promises

### Image Optimization
**Symptom**: Large images slow down page loads
**Solution**: Always use Next.js `<Image>` component with `sizes` prop
Enter fullscreen mode Exit fullscreen mode


tsx
import Image from 'next/image';

src="/photo.jpg"
alt="Description"
width={800}
height={600}
sizes="(max-width: 768px) 100vw, 50vw"
/>


## Deployment Checklist

Before deploying:
1. ✅ Run `pnpm build` locally (catches build errors)
2. ✅ Verify environment variables in Vercel dashboard
3. ✅ Test database migrations in staging
4. ✅ Check API rate limits and timeouts
5. ✅ Review bundle size (`pnpm build` shows size)

Vercel config:
- Build command: `pnpm build`
- Output directory: `.next`
- Install command: `pnpm install`
- Development command: `pnpm dev`
Enter fullscreen mode Exit fullscreen mode

4.2 Windsurf Configuration

Windsurf (from Codeium) introduced Wave 8 in May 2025, which fundamentally changed its rules architecture from single-file simplicity to a sophisticated directory-based system with GUI-managed activation modes.

4.2.1 Wave 8+ Architecture (Current)

Core Concepts:

  • Directory-based: .windsurf/rules/*.md (multiple focused files)
  • GUI-managed: Rules configured via Settings UI, not just file editing
  • Activation modes: Four distinct triggers (Manual, Always On, Model Decision, Glob Pattern)
  • Character limits: 6,000 chars per file, 12,000 total combined

File Structure:

my-project/
├── .windsurf/
│   └── rules/
│       ├── 01-project-overview.md      # Always On
│       ├── 02-architecture.md          # Always On
│       ├── 03-typescript-rules.md      # Glob: **/*.{ts,tsx}
│       ├── 04-python-rules.md          # Glob: **/*.py
│       ├── 05-testing-guide.md         # Manual (on demand)
│       └── 06-security-review.md       # Model Decision
├── .windsurfrules                       # Legacy single-file (still works)
└── src/
Enter fullscreen mode Exit fullscreen mode

Global Rules Location:

~/.codeium/windsurf/memories/global_rules.md
Enter fullscreen mode Exit fullscreen mode

4.2.2 YAML Frontmatter + Markdown Body Format

While Windsurf primarily uses plain Markdown, you can include optional YAML frontmatter for metadata:

---
version: 1.2.0
priority: high
applies_to: ["src/**/*.ts", "app/**/*.tsx"]
last_updated: 2025-11-29
---

# TypeScript Coding Standards

## Type Safety Requirements

### Strict Mode Configuration
Ensure `tsconfig.json` has:
Enter fullscreen mode Exit fullscreen mode


json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUncheckedIndexedAccess": true
}
}


### Type Annotations
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ ALWAYS: Explicit return types
function calculateTotal(items: CartItem[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ NEVER: Implicit return type
function calculateTotal(items: CartItem[]) {
return items.reduce((sum, item) => sum + item.price, 0);
}


### Type Guards
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ Use type predicates for narrowing
function isError(value: unknown): value is Error {
return value instanceof Error;
}

async function fetchData() {
try {
const data = await api.get('/data');
return { success: true, data };
} catch (error) {
if (isError(error)) {
return { success: false, error: error.message };
}
return { success: false, error: 'Unknown error occurred' };
}
}


## Naming Conventions

| Element | Convention | Example |
|---------|-----------|---------|
| Variables | camelCase | `userName`, `isLoading` |
| Functions | camelCase | `fetchUser()`, `calculateTotal()` |
| Types/Interfaces | PascalCase | `User`, `ApiResponse<T>` |
| Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT`, `API_BASE_URL` |
| Files | kebab-case | `user-profile.tsx`, `api-client.ts` |

## Import Organization
Enter fullscreen mode Exit fullscreen mode


typescript
// 1. External dependencies (React, libraries)
import { useState, useEffect } from 'react';
import { z } from 'zod';

// 2. Internal modules (@ alias imports)
import { Button } from '@/components/ui/button';
import { trpc } from '@/lib/trpc/client';

// 3. Relative imports
import { UserCard } from './UserCard';
import type { User } from './types';

// 4. CSS/styles (if any)
import './styles.css';

Enter fullscreen mode Exit fullscreen mode

YAML Frontmatter Fields (Optional):

Field Purpose Example
version Track rule file versions 1.2.0
priority Conflict resolution high, medium, low
applies_to File pattern hints ["src/**/*.ts"]
last_updated Maintenance tracking 2025-11-29

Note: Frontmatter is informational—Windsurf doesn't programmatically enforce these fields. Activation is controlled through the GUI.

4.2.3 Activation Modes (Wave 8 Feature)

How to Configure:

  1. Open Windsurf
  2. Navigate to: Settings → Rules
  3. Click on any rule file
  4. Select activation mode from dropdown

The Four Modes:

1. Always On

  • Behavior: Rule is included in every Cascade interaction
  • Use for: Core project standards, universal conventions
  • Token impact: High (always loaded)
  • Example files: 01-project-overview.md, 02-architecture.md
# 01-project-overview.md (Always On)

# Project: E-Commerce Platform

**Tech Stack**: Next.js 15, TypeScript, PostgreSQL, tRPC
**Architecture**: Monorepo managed by Turborepo
**Deployment**: Vercel (production), Railway (staging)

## Universal Standards
- All commits follow Conventional Commits format
- All PRs require at least one approval
- Code coverage must remain above 80%
- Environment variables never committed to git
Enter fullscreen mode Exit fullscreen mode

2. Glob Pattern

  • Behavior: Rule applies when working with files matching pattern
  • Use for: Language-specific or directory-specific rules
  • Token impact: Medium (conditional loading)
  • Pattern syntax: Standard glob (gitignore-style)
# 03-typescript-rules.md (Glob: **/*.{ts,tsx})

# TypeScript-Specific Rules

These rules apply ONLY to TypeScript files.

## Async Patterns
Always use async/await, never Promise.then():
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ CORRECT
async function fetchUser(id: string) {
try {
const user = await api.get(/users/${id});
return user;
} catch (error) {
logger.error('Failed to fetch user', { id, error });
throw new AppError('User fetch failed', 500);
}
}

// ❌ WRONG
function fetchUser(id: string) {
return api.get(/users/${id})
.then(user => user)
.catch(error => {
console.log(error); // Bad error handling
});
}

Enter fullscreen mode Exit fullscreen mode

Glob Pattern Examples:

Pattern Matches Doesn't Match
**/*.ts src/app.ts, lib/utils.ts src/app.tsx, src/app.js
**/*.{ts,tsx} src/app.ts, src/Button.tsx src/app.js
src/** src/app.ts, src/lib/utils.ts tests/app.test.ts
!**/*.test.ts Exclude test files
{frontend,backend}/** Both frontend/ and backend/ Other dirs

3. Model Decision

  • Behavior: Cascade (AI) decides when to apply based on description
  • Use for: Context-specific guidelines (security, performance, migrations)
  • Token impact: Low (only when relevant)
  • Requires: Clear natural language description of when to use

Configuration in GUI:

Activation Mode: Model Decision
Description: "Apply when the user's request involves authentication, 
user data handling, or API security concerns"
Enter fullscreen mode Exit fullscreen mode

File Content:

# 06-security-review.md (Model Decision)

# Security Guidelines

**When to use this rule**: Authentication, authorization, data validation, 
API security, credential management, or reviewing code for security issues.

## Authentication Best Practices

### JWT Handling
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ CORRECT: HttpOnly cookies
export async function setAuthTokens(
res: Response,
accessToken: string,
refreshToken: string
) {
res.cookie('accessToken', accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 15 * 60 * 1000, // 15 minutes
});

res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
});
}

// ❌ NEVER: localStorage or sessionStorage
localStorage.setItem('token', accessToken); // Vulnerable to XSS


### Input Validation
ALWAYS validate and sanitize:
Enter fullscreen mode Exit fullscreen mode


typescript
import { z } from 'zod';

const LoginSchema = z.object({
email: z.string().email().max(255),
password: z.string().min(12).max(128),
});

export async function login(req: Request) {
// Parse and validate
const body = LoginSchema.parse(req.body);

// body is now type-safe and validated
const user = await authenticateUser(body.email, body.password);
}


### SQL Injection Prevention
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ CORRECT: Parameterized queries
const user = await db
.select()
.from(users)
.where(eq(users.email, email)) // Drizzle ORM handles escaping
.limit(1);

// ❌ NEVER: String concatenation
const query = SELECT * FROM users WHERE email = '${email}'; // SQL injection!


## Secrets Management

### Environment Variables
Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ Validate environment variables at startup
import { z } from 'zod';

const envSchema = z.object({
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
API_KEY: z.string().min(20),
});

export const env = envSchema.parse(process.env);

// ❌ NEVER hardcode or commit secrets
const apiKey = 'sk_live_abcd1234...'; // SECURITY VIOLATION


### API Key Storage
- Use secret management (Vercel Environment Variables, AWS Secrets Manager)
- Rotate keys every 90 days
- Use different keys for dev/staging/production

## Common Vulnerabilities Checklist

When reviewing code, check for:
- [ ] XSS: Is user input sanitized before rendering?
- [ ] SQL Injection: Are queries parameterized?
- [ ] CSRF: Are state-changing endpoints protected?
- [ ] Open Redirect: Are redirect URLs validated?
- [ ] Rate Limiting: Are public endpoints protected?
Enter fullscreen mode Exit fullscreen mode

4. Manual

  • Behavior: Rule only applies when explicitly mentioned in chat
  • Use for: Specialized workflows, testing guidelines, migration procedures
  • Token impact: None (unless invoked)
  • Invocation: @rulename or via dropdown menu
# 05-testing-guide.md (Manual)

# Comprehensive Testing Guide

**Usage**: Invoke this rule with @testing-guide when writing or updating tests.

## Test Structure (AAA Pattern)

Enter fullscreen mode Exit fullscreen mode


typescript
import { describe, it, expect, beforeEach, vi } from 'vitest';

describe('UserService', () => {
let service: UserService;
let mockDb: MockDatabase;

beforeEach(() => {
// ARRANGE: Set up test environment
mockDb = createMockDatabase();
service = new UserService(mockDb);
});

it('creates user with valid data', async () => {
// ARRANGE: Prepare test data
const userData = {
email: 'test@example.com',
name: 'Test User',
};

// ACT: Execute the function being tested
const result = await service.createUser(userData);

// ASSERT: Verify the outcome
expect(result.success).toBe(true);
expect(result.data).toMatchObject(userData);
expect(mockDb.insert).toHaveBeenCalledOnce();
Enter fullscreen mode Exit fullscreen mode

});

it('handles validation errors', async () => {
// ARRANGE: Invalid data
const invalidData = {
email: 'not-an-email',
name: '',
};

// ACT
const result = await service.createUser(invalidData);

// ASSERT
expect(result.success).toBe(false);
expect(result.error).toContain('validation');
Enter fullscreen mode Exit fullscreen mode

});
});


## Mocking Strategies

### Mock External APIs
Enter fullscreen mode Exit fullscreen mode


typescript
import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
rest.get('https://api.example.com/users', (req, res, ctx) => {
return res(
ctx.json([
{ id: '1', name: 'User 1' },
{ id: '2', name: 'User 2' },
])
);
})
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());


### Mock Database
Enter fullscreen mode Exit fullscreen mode


typescript
const mockDb = {
query: {
users: {
findFirst: vi.fn(),
findMany: vi.fn(),
},
},
insert: vi.fn(),
update: vi.fn(),
};


## Coverage Requirements

| Test Type | Target Coverage | Command |
|-----------|----------------|---------|
| Unit | 80% minimum | `pnpm test` |
| Integration | 70% minimum | `pnpm test:integration` |
| E2E | Critical paths only | `pnpm test:e2e` |

## Test Naming Convention

Enter fullscreen mode Exit fullscreen mode


typescript
// Pattern: "should [expected behavior] when [condition]"

it('should return user when valid ID provided', async () => { ... });
it('should throw error when user not found', async () => { ... });
it('should validate email format before saving', async () => { ... });


## E2E Test Template (Playwright)

Enter fullscreen mode Exit fullscreen mode


typescript
import { test, expect } from '@playwright/test';

test.describe('User Authentication Flow', () => {
test('should complete signup and login', async ({ page }) => {
// Sign up
await page.goto('/signup');
await page.fill('[name="email"]', 'newuser@example.com');
await page.fill('[name="password"]', 'SecurePassword123!');
await page.fill('[name="confirmPassword"]', 'SecurePassword123!');
await page.click('button[type="submit"]');

// Verify redirect to dashboard
await expect(page).toHaveURL('/dashboard');

// Log out
await page.click('[data-testid="user-menu"]');
await page.click('text=Logout');

// Log back in
await page.goto('/login');
await page.fill('[name="email"]', 'newuser@example.com');
await page.fill('[name="password"]', 'SecurePassword123!');
await page.click('button[type="submit"]');

// Verify successful login
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('text=Welcome back')).toBeVisible();
Enter fullscreen mode Exit fullscreen mode

});
});

Enter fullscreen mode Exit fullscreen mode

4.2.4 Character Limits and Token Management

Hard Limits:

  • Per file: 6,000 characters maximum
  • Total combined: 12,000 characters (global + workspace rules)
  • What happens if exceeded: Content is silently truncated—no warning

Token Efficiency Strategies:

Strategy 1: XML-Style Tags for Dense Organization

# Comprehensive Project Rules (4,800 chars - within limit)

<projectContext>
**Stack**: Next.js 15, TypeScript, PostgreSQL, tRPC
**Team Size**: 8 engineers
**Deployment**: Vercel
</projectContext>

<codingStandards>
- TypeScript strict mode
- Functional components only
- Zod for validation
- TanStack Query for server state
</codingStandards>

<architecturePatterns>
## Feature-Sliced Design
Enter fullscreen mode Exit fullscreen mode

src/
├── features/
│ ├── auth/
│ ├── users/
│ └── products/

</architecturePatterns>

<errorHandling>
## Pattern
Enter fullscreen mode Exit fullscreen mode


typescript
try {
await operation();
} catch (error) {
logger.error('Context', { error });
throw new AppError('User message', 500);
}

</errorHandling>

<safetyRestrictions>
- NEVER commit secrets
- ALWAYS validate inputs
- NO console.log in production
</safetyRestrictions>

<testingRequirements>
- 80% coverage minimum
- Unit: Vitest
- E2E: Playwright
</testingRequirements>
Enter fullscreen mode Exit fullscreen mode

Why XML tags work:

  • Clear semantic boundaries
  • Easy to scan (both human and AI)
  • Sections can be rearranged without breaking structure
  • Reduces need for verbose headers

Strategy 2: Reference External Docs

# Project Rules (Main File - 2,000 chars)

<overview>
Next.js 15 e-commerce platform. See architecture details: @docs/architecture.md
</overview>

<standards>
For complete TypeScript rules: @docs/typescript.md
For API patterns: @docs/api-conventions.md
For testing guide: @docs/testing.md
</standards>

<quickReference>
## Most Critical Rules
1. TypeScript strict mode
2. Server Components by default
3. Zod for all validation
4. TanStack Query for data fetching
5. Error boundary on every route
</quickReference>
Enter fullscreen mode Exit fullscreen mode

Strategy 3: Multi-File Modular Approach

Instead of one 10,000 char file:

.windsurf/rules/
├── 01-core.md           (1,500 chars - Always On)
├── 02-typescript.md     (2,000 chars - Glob: **/*.ts)
├── 03-react.md          (2,000 chars - Glob: **/*.tsx)
├── 04-testing.md        (2,500 chars - Manual)
└── 05-security.md       (2,000 chars - Model Decision)

Total: 10,000 chars, but max 3,500 loaded at once
Enter fullscreen mode Exit fullscreen mode

4.2.5 Production Examples

Example 1: SaaS Application (Next.js + Supabase)

---
version: 1.0.0
applies_to: ["app/**/*", "components/**/*"]
---

# SaaS Application Rules

<projectContext>
**Product**: Team collaboration platform
**Stack**: Next.js 15, TypeScript, Supabase, Tailwind
**Architecture**: Multi-tenant SaaS
**Auth**: Supabase Auth with Row-Level Security (RLS)
</projectContext>

<multiTenancy>
## Every Query Must Include Tenant Context

Enter fullscreen mode Exit fullscreen mode


typescript
// ✅ CORRECT: Filter by org_id
const projects = await supabase
.from('projects')
.select('*')
.eq('org_id', user.org_id); // Always filter by organization

// ❌ NEVER: Query without tenant filter
const allProjects = await supabase
.from('projects')
.select('*'); // SECURITY RISK: Leaks data across orgs


## Database Policies
All tables have RLS enabled:
Enter fullscreen mode Exit fullscreen mode


sql
CREATE POLICY "Users can only see their org data"
ON projects FOR SELECT
USING (org_id = auth.current_org_id());

</multiTenancy>

<componentPatterns>
## Server Component Pattern
Enter fullscreen mode Exit fullscreen mode


tsx
// app/dashboard/page.tsx
export default async function DashboardPage() {
const supabase = createServerComponentClient();
const { data: projects } = await supabase
.from('projects')
.select('*')
.order('created_at', { ascending: false });

return ;
}


## Client Component Pattern
Enter fullscreen mode Exit fullscreen mode


tsx
'use client';

import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';

export function CreateProject() {
const supabase = createClientComponentClient();

async function handleCreate(data: FormData) {
const { error } = await supabase
.from('projects')
.insert({ name: data.get('name'), org_id: user.org_id });

if (error) toast.error(error.message);
Enter fullscreen mode Exit fullscreen mode

}

return

...;
}
</componentPatterns>

<authPatterns>
## Protect Server Components
Enter fullscreen mode Exit fullscreen mode


tsx
import { redirect } from 'next/navigation';
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';

export default async function ProtectedPage() {
const supabase = createServerComponentClient();
const { data: { session } } = await supabase.auth.getSession();

if (!session) {
redirect('/login');
}

// Page content...
}


## Middleware for Route Protection
Enter fullscreen mode Exit fullscreen mode


typescript
// middleware.ts
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs';

export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const supabase = createMiddlewareClient({ req, res });
const { data: { session } } = await supabase.auth.getSession();

// Protect /dashboard routes
if (req.nextUrl.pathname.startsWith('/dashboard') && !session) {
return NextResponse.redirect(new URL('/login', req.url));
}

return res;
}

</authPatterns>

<realtimePatterns>
## Subscribe to Changes
Enter fullscreen mode Exit fullscreen mode


typescript
'use client';

useEffect(() => {
const channel = supabase
.channel('projects-changes')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'projects',
filter: org_id=eq.${orgId},
},
(payload) => {
// Handle realtime update
queryClient.invalidateQueries(['projects']);
}
)
.subscribe();

return () => {
supabase.removeChannel(channel);
};
}, [orgId]);

</realtimePatterns>

<deploymentChecklist>
Before deploying:
1. ✅ RLS enabled on all tables
2. ✅ Org_id filter in all queries
3. ✅ Environment variables in Vercel
4. ✅ Database migrations applied
5. ✅ Supabase Edge Functions deployed
</deploymentChecklist>
Enter fullscreen mode Exit fullscreen mode

Example 2: FastAPI Microservice

---
version: 2.1.0
applies_to: ["app/**/*.py", "tests/**/*.py"]
---

# FastAPI Microservice Rules

<architecture>
**Pattern**: Hexagonal Architecture
**Database**: PostgreSQL with AsyncPG
**Messaging**: RabbitMQ
**Observability**: OpenTelemetry + Grafana
</architecture>

<directoryStructure>
Enter fullscreen mode Exit fullscreen mode

app/
├── api/
│ ├── routes/ # FastAPI routers
│ └── dependencies.py # Dependency injection
├── core/
│ ├── config.py # Settings management
│ └── security.py # Auth utilities
├── domain/
│ ├── models/ # Business entities
│ ├── services/ # Business logic
│ └── repositories/ # Data access interface
├── infrastructure/
│ ├── database/ # Database implementation
│ ├── messaging/ # RabbitMQ implementation
│ └── external_apis/ # External service clients
└── tests/
├── unit/
├── integration/
└── e2e/

</directoryStructure>

<dependencyInjection>
## FastAPI Dependencies Pattern

Enter fullscreen mode Exit fullscreen mode


python

app/api/dependencies.py

from typing import Annotated
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.infrastructure.database import get_db_session

Type alias for cleaner route signatures

DbSession = Annotated[AsyncSession, Depends(get_db_session)]

app/api/routes/users.py

from fastapi import APIRouter
from app.api.dependencies import DbSession
from app.domain.services import UserService

router = APIRouter()

@router.get("/users/{user_id}")
async def get_user(
user_id: str,
db: DbSession, # Auto-injected
current_user: CurrentUser, # Auth dependency
) -> UserResponse:
service = UserService(db)
user = await service.get_by_id(user_id)
return UserResponse.from_domain(user)

</dependencyInjection>

<repositoryPattern>
## Abstract Repository Interface

Enter fullscreen mode Exit fullscreen mode


python

app/domain/repositories/user_repository.py

from abc import ABC, abstractmethod
from typing import Optional
from app.domain.models import User

class UserRepository(ABC):
@abstractmethod
async def get_by_id(self, user_id: str) -> Optional[User]:
pass

@abstractmethod
async def save(self, user: User) -> User:
    pass
Enter fullscreen mode Exit fullscreen mode

app/infrastructure/database/repositories/user_repository_impl.py

from sqlalchemy import select
from app.domain.repositories import UserRepository

class UserRepositoryImpl(UserRepository):
def init(self, session: AsyncSession):
self.session = session

async def get_by_id(self, user_id: str) -> Optional[User]:
    stmt = select(User).where(User.id == user_id)
    result = await self.session.execute(stmt)
    return result.scalar_one_or_none()

async def save(self, user: User) -> User:
    self.session.add(user)
    await self.session.commit()
    await self.session.refresh(user)
    return user
Enter fullscreen mode Exit fullscreen mode
</repositoryPattern>

<errorHandling>
## Custom Exception Hierarchy

Enter fullscreen mode Exit fullscreen mode


python

app/core/exceptions.py

class AppException(Exception):
"""Base application exception"""
def init(self, message: str, status_code: int = 500):
self.message = message
self.status_code = status_code
super().init(message)

class NotFoundError(AppException):
def init(self, entity: str, entity_id: str):
super().init(
f"{entity} with id {entity_id} not found",
status_code=404
)

class ValidationError(AppException):
def init(self, message: str):
super().init(message, status_code=400)

app/api/exception_handlers.py

from fastapi import Request, status
from fastapi.responses import JSONResponse

@app.exception_handler(AppException)
async def app_exception_handler(request: Request, exc: AppException):
return JSONResponse(
status_code=exc.status_code,
content={
"error": True,
"code": exc.class.name,
"message": exc.message,
},
)

Usage in routes

@router.get("/users/{user_id}")
async def get_user(user_id: str, db: DbSession):
user = await service.get_by_id(user_id)
if not user:
raise NotFoundError("User", user_id)
return UserResponse.from_domain(user)

</errorHandling>

<asyncPatterns>
## Database Session Management

Enter fullscreen mode Exit fullscreen mode


python

✅ CORRECT: Async context manager

async with get_db_session() as session:
result = await session.execute(query)
await session.commit()

❌ NEVER: Forget to await

session = get_db_session() # Missing await!
result = session.execute(query) # Will fail

Concurrent Operations

import asyncio

# ✅ Parallel independent queries
user, posts, comments = await asyncio.gather(
    user_repo.get_by_id(user_id),
    post_repo.get_by_user(user_id),
    comment_repo.get_by_user(user_id),
)

# ❌ Sequential when could be parallel
user = await user_repo.get_by_id(user_id)
posts = await post_repo.get_by_user(user_id)  # Waited unnecessarily
comments = await comment_repo.get_by_user(user_id)
Enter fullscreen mode Exit fullscreen mode

Pytest Fixtures

# tests/conftest.py
import pytest
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from app.infrastructure.database import Base

@pytest.fixture
async def db_session():
    engine = create_async_engine("postgresql+asyncpg://test")
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    async with AsyncSession(engine) as session:
        yield session

    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)

@pytest.fixture
def user_service(db_session):
    repo = UserRepositoryImpl(db_session)
    return UserService(repo)

# tests/unit/services/test_user_service.py
@pytest.mark.asyncio
async def test_create_user(user_service):
    user_data = {"email": "test@example.com", "name": "Test"}
    user = await user_service.create(user_data)

    assert user.id is not None
    assert user.email == "test@example.com"
Enter fullscreen mode Exit fullscreen mode

---

### **4.3 Claude Code (CLAUDE.md)**

Claude Code revolutionized AI coding by introducing **persistent project memory** through the `CLAUDE.md` file, which automatically loads at session start without requiring repeated explanations.

#### **4.3.1 File Location Hierarchy**

**Search Order (Priority):**

1. **User-level global** (personal preferences):
Enter fullscreen mode Exit fullscreen mode

~/.claude/CLAUDE.md

   - Applies to ALL projects
   - Your universal coding style, preferences, response format

2. **Project root** (team-shared):
Enter fullscreen mode Exit fullscreen mode

./CLAUDE.md
or
./.claude/CLAUDE.md

   - Project-specific standards
   - Version controlled, shared with team

3. **Subdirectory** (module-specific):
Enter fullscreen mode Exit fullscreen mode

./packages/frontend/CLAUDE.md
./services/api/CLAUDE.md

   - Loaded on-demand when working in that directory
   - Useful for monorepos with different conventions per package

4. **Organization-level** (Enterprise Linux/Unix):
Enter fullscreen mode Exit fullscreen mode

/etc/claude-code/CLAUDE.md

   - Centralized company-wide policies
   - Requires admin setup

**Loading Behavior:**
- Claude starts at current working directory
- Recurses **UP** the filesystem tree loading all CLAUDE.md files
- Combines them (more specific overrides more general)
- For subdirectories, loads on-demand when reading files in that subtree

**Practical Example:**

Enter fullscreen mode Exit fullscreen mode

my-monorepo/
├── CLAUDE.md # Loaded: Universal monorepo rules
├── packages/
│ ├── frontend/
│ │ ├── CLAUDE.md # Loaded: When editing frontend files
│ │ └── src/
│ └── backend/
│ ├── CLAUDE.md # Loaded: When editing backend files
│ └── src/
└── ~/.claude/CLAUDE.md # Loaded: Your personal preferences


If you edit `packages/frontend/src/App.tsx`, Claude loads:
1. `~/.claude/CLAUDE.md` (your preferences)
2. `my-monorepo/CLAUDE.md` (universal rules)
3. `my-monorepo/packages/frontend/CLAUDE.md` (frontend-specific)

#### **4.3.2 The Canonical 8-Section Structure**

Based on Anthropic's internal usage and community best practices:

Enter fullscreen mode Exit fullscreen mode


markdown

[Project Name] - [One-line Description]

Version: 1.0.0

Last Updated: 2025-11-29

Maintainer: @username


1. PROJECT OVERVIEW (30-100 words)

Brief description of what this project does and its primary goal.

Example:
Full-stack e-commerce platform built with Next.js and PostgreSQL.
Supports multi-tenant SaaS model with row-level security.
Primary goal: Handle 10k concurrent users with <100ms API response times.


2. TECHNOLOGY STACK

Frontend

  • Framework: Next.js 15.1 (App Router)
  • Language: TypeScript 5.4 (strict mode)
  • Styling: Tailwind CSS 4.0, shadcn/ui
  • State Management:
    • Server State: TanStack Query v5
    • Client State: Zustand 4.5
    • Form State: React Hook Form 7.5 + Zod 3.23

Backend

  • Runtime: Node.js 20.11 LTS
  • Framework: Express.js + tRPC 11
  • Database: PostgreSQL 16
  • ORM: Drizzle ORM 0.35
  • Authentication: NextAuth.js v5

DevOps

  • Package Manager: pnpm 9.0 (NOT npm/yarn)
  • Monorepo: Turborepo 2.0
  • Testing: Vitest 2.0, Playwright 1.45
  • CI/CD: GitHub Actions
  • Hosting: Vercel (prod), Railway (staging)

3. PROJECT STRUCTURE

root/
├── apps/
│   ├── web/                # Next.js frontend
│   │   ├── app/           # App Router pages
│   │   ├── components/    # React components
│   │   └── lib/           # Client utilities
│   └── api/               # Standalone API (if separate)
├── packages/
│   ├── ui/                # Shared component library
│   ├── database/          # Drizzle schema & migrations
│   ├── types/             # Shared TypeScript types
│   └── config/            # Shared configs (ESLint, TS, etc.)
├── docs/                  # Documentation
├── scripts/               # Build/deployment scripts
└── .github/               # CI/CD workflows
Enter fullscreen mode Exit fullscreen mode

Key Directories:

  • apps/web/app/: Next.js routes using App Router (NOT Pages Router)
  • apps/web/components/ui/: shadcn/ui primitives
  • apps/web/components/features/: Feature-specific components
  • packages/database/: Drizzle schema definitions
  • apps/web/lib/api/: tRPC routers and procedures

4. CODING STANDARDS

TypeScript Rules

Type Safety

// ✅ ALWAYS: Explicit return types on functions
export function calculateTotal(items: CartItem[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ NEVER: Implicit any or missing return type
export function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Error Handling

// ✅ CORRECT: Explicit try-catch with logging
export async function fetchUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.query.users.findFirst({
      where: eq(users.id, id)
    });

    if (!user) {
      return { success: false, error: 'User not found' };
    }

    return { success: true, data: user };
  } catch (error) {
    logger.error('Failed to fetch user', { id, error });
    return { success: false, error: 'Database error' };
  }
}

// ❌ NEVER: Silent error swallowing
export async function fetchUser(id: string) {
  try {
    return await db.query.users.findFirst({ where: eq(users.id, id) });
  } catch {
    return null; // Silent failure!
  }
}
Enter fullscreen mode Exit fullscreen mode

React Patterns

Component Structure

// ✅ PREFERRED: Named export with TypeScript interface
interface UserCardProps {
  user: User;
  onEdit: (id: string) => void;
  className?: string;
}

export function UserCard({ user, onEdit, className }: UserCardProps) {
  return (
    <div className={cn('rounded-lg border p-4', className)}>
      <h3>{user.name}</h3>
      <Button onClick={() => onEdit(user.id)}>Edit</Button>
    </div>
  );
}

// ❌ AVOID: Default export with inline types
export default function UserCard({ user, onEdit }: {
  user: any;
  onEdit: Function;
}) {
  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Server vs Client Components

// ✅ Server Component (default - no directive)
async function UsersPage() {
  // Can directly query database in Server Components
  const users = await db.query.users.findMany();

  return <UserList users={users} />;
}

// ✅ Client Component (only when needed)
'use client';

import { useState } from 'react';

export function InteractiveCounter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

// ❌ WRONG: Adding 'use client' unnecessarily
'use client';

export function StaticHeader() {
  return <h1>Welcome</h1>; // No interactivity - should be Server Component
}
Enter fullscreen mode Exit fullscreen mode

Import Organization

// 1. React and third-party libraries
import { useState, useEffect } from 'react';
import { z } from 'zod';

// 2. Internal packages (monorepo)
import { Button } from '@repo/ui';
import { User } from '@repo/types';

// 3. Application modules (@ alias)
import { trpc } from '@/lib/trpc/client';
import { cn } from '@/lib/utils';

// 4. Relative imports
import { UserCard } from './UserCard';
import type { UserCardProps } from './types';

// 5. Styles (if any)
import './styles.css';
Enter fullscreen mode Exit fullscreen mode

5. COMMON COMMANDS

Development

pnpm dev                    # Start dev server (localhost:3000)
pnpm dev --filter=web       # Start only web app (monorepo)
pnpm build                  # Production build
pnpm lint                   # Run ESLint
pnpm type-check             # TypeScript validation
pnpm format                 # Run Prettier
Enter fullscreen mode Exit fullscreen mode

Testing

pnpm test                   # Run Vitest unit tests
pnpm test:watch             # Watch mode
pnpm test:coverage          # Generate coverage report
pnpm test:e2e               # Run Playwright E2E tests
pnpm test:e2e:ui            # Playwright UI mode
Enter fullscreen mode Exit fullscreen mode

Database

pnpm db:push                # Push schema changes to database
pnpm db:studio              # Open Drizzle Studio GUI
pnpm db:generate            # Generate migration files
pnpm db:migrate             # Apply migrations
pnpm db:seed                # Seed database with test data
Enter fullscreen mode Exit fullscreen mode

Deployment

pnpm deploy:staging         # Deploy to Railway staging
pnpm deploy:production      # Deploy to Vercel production
Enter fullscreen mode Exit fullscreen mode

6. TESTING REQUIREMENTS

Unit Tests (Vitest)

  • Location: src/**/*.test.ts (colocated with source)
  • Coverage: Minimum 80% for business logic
  • Run before commit: Pre-commit hook runs affected tests
import { describe, it, expect, beforeEach } from 'vitest';
import { calculateDiscount } from './pricing';

describe('calculateDiscount', () => {
  it('applies 10% discount for orders over $100', () => {
    expect(calculateDiscount(150)).toBe(15);
  });

  it('returns 0 for orders under $100', () => {
    expect(calculateDiscount(50)).toBe(0);
  });

  it('handles edge case of exactly $100', () => {
    expect(calculateDiscount(100)).toBe(0);
  });
});
Enter fullscreen mode Exit fullscreen mode

Integration Tests

  • Location: tests/integration/
  • Focus: API endpoints, database operations
  • Use: MSW for mocking external APIs

E2E Tests (Playwright)

  • Location: tests/e2e/
  • Focus: Critical user flows only
  • Run: On PR to main branch
import { test, expect } from '@playwright/test';

test('user can complete checkout', async ({ page }) => {
  await page.goto('/shop');

  // Add items to cart
  await page.click('[data-testid="add-to-cart-1"]');
  await page.click('[data-testid="add-to-cart-2"]');

  // Navigate to checkout
  await page.click('[data-testid="cart-button"]');
  await page.click('text=Checkout');

  // Fill shipping info
  await page.fill('[name="email"]', 'test@example.com');
  await page.fill('[name="address"]', '123 Main St');

  // Complete purchase
  await page.click('button:has-text("Place Order")');

  // Verify success
  await expect(page.locator('text=Order confirmed')).toBeVisible();
});
Enter fullscreen mode Exit fullscreen mode

7. KNOWN ISSUES & PITFALLS

Issue 1: Hot Reload with tRPC

Symptom: Changes to tRPC routers don't reflect in frontend

Cause: tRPC type generation lags behind file changes

Solution: Restart dev server when adding/removing procedures

Tracking: Issue #123

Issue 2: Server Component Hydration Errors

Symptom: "Text content did not match" errors in console

Cause: Mixing server/client rendering incorrectly

Solution:

// ✅ Ensure async server components await all data
async function UserPage() {
  const user = await fetchUser(); // Must await
  return <div>{user.name}</div>;
}

// ❌ Don't mix server async with client hooks
async function UserPage() {
  const [data, setData] = useState(); // ERROR: Can't use hooks in Server Component
  const user = await fetchUser();
  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Issue 3: Drizzle Query Performance

Symptom: Slow queries for user dashboards (>2 seconds)

Cause: N+1 query problem with relations

Solution: Use Drizzle's with for eager loading

// ✅ Single query with eager loading
const users = await db.query.users.findMany({
  with: {
    posts: true,
    profile: true,
  },
});

// ❌ N+1: Queries once per user
const users = await db.query.users.findMany();
for (const user of users) {
  user.posts = await db.query.posts.findMany({
    where: eq(posts.userId, user.id)
  });
}
Enter fullscreen mode Exit fullscreen mode

Issue 4: Environment Variables in Client Components

Symptom: process.env.NEXT_PUBLIC_API_URL is undefined

Cause: Forgot NEXT_PUBLIC_ prefix for client-side env vars

Solution: All client-accessible env vars MUST have prefix

# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com  # ✅ Available client-side
DATABASE_URL=postgresql://...                # ❌ Server-only
Enter fullscreen mode Exit fullscreen mode

8. IMPORTANT NOTES

API Rate Limiting

  • Public endpoints: 100 requests/minute per IP
  • Authenticated: 1000 requests/minute per user
  • Implemented via: Upstash Redis rate limiter

Authentication

  • JWT Expiration: Access tokens expire after 15 minutes
  • Refresh Tokens: Valid for 7 days, rotated on use
  • Storage: HttpOnly cookies (NEVER localStorage)

Database Constraints

  • Max connections: 20 (PgBouncer pool)
  • Query timeout: 30 seconds
  • Row-level security: Enabled on all tables

File Uploads

  • Max size: 10MB per file
  • Allowed types: Images (JPEG, PNG, WebP), PDFs
  • Storage: Cloudinary (dev/staging), AWS S3 (production)

Deployment

  • Auto-deploy: Merges to main trigger production deploy
  • Preview: All PRs get unique preview URL
  • Rollback: Use Vercel dashboard for instant rollback

Monitoring

  • Errors: Sentry for error tracking
  • Performance: Vercel Analytics
  • Logs: Axiom for centralized logging

Additional Context Files

For detailed information, reference these files:

  • Architecture diagrams: @docs/architecture.md
  • API documentation: @docs/api-reference.md
  • Database schema: @packages/database/schema.ts
  • Deployment guide: @docs/deployment.md

How to Update This File

  1. When to update:

    • Tech stack changes (new library, version upgrade)
    • New coding patterns emerge
    • Known issues discovered
    • Team conventions evolve
  2. Process:

    • Create PR with changes to CLAUDE.md
    • Require 1 team approval
    • Update Last Updated date
    • Increment version (semver)
  3. Keep concise:

    • Target: Under 50KB (this file: ~12KB)
    • Link to external docs for details
    • Focus on high-impact rules

This CLAUDE.md structure has been validated with 50+ production projects. It represents the optimal balance between comprehensiveness and brevity, providing Claude Code with maximum effectiveness while remaining maintainable.


---

### **4.4 Aider Configuration**

Aider pioneered the **convention file** approach, where a team-shared `CONVENTIONS.md` loaded via `.aider.conf.yml` provides persistent context without cluttering chat history.

#### **4.4.1 `.aider.conf.yml` Complete Schema**

Aider uses a **flat YAML structure** where keys match command-line flags. The config merges in this order:

1. `./.aider.conf.yml` (project root - highest priority)
2. Parent directories up to filesystem root
3. `~/.aider.conf.yml` (global user config)
4. Environment variables (`AIDER_MODEL`, etc.)
5. Command-line flags (override everything)

**Complete Configuration Reference:**

Enter fullscreen mode Exit fullscreen mode


yaml

AIDER CONFIGURATION FILE

Location: .aider.conf.yml (project root)

Docs: https://aider.chat/docs/config.html

MODELS

Main chat model (does the coding)

model: claude-3-5-sonnet-20241022

Weak model for commit messages, file summaries

weak-model: gpt-4o-mini

Editor model for architect mode (optional)

editor-model: claude-3-5-sonnet-20241022

API configuration

api-key: sk-xxx # Don't commit! Use env vars instead

api-base: https://api.openai.com/v1

Model aliases for quick switching

alias:

  • "sonnet:claude-3-5-sonnet-20241022"
  • "gpt4:gpt-4o"
  • "fast:gpt-4o-mini"
  • "local:ollama/qwen2.5-coder"

EDIT BEHAVIOR

How AI returns code changes

edit-format: diff # Options: diff, diff-fenced, udiff, whole, editor-diff, editor-whole

Architect mode (two-step editing)

architect: false
auto-accept-architect: true
editor-edit-format: editor-diff

RULES & CONTEXT

Inline rules (short guidelines)

rules:

  • "Use TypeScript strict mode for all code"
  • "Follow functional programming patterns"
  • "Prefer composition over inheritance"
  • "Add JSDoc comments for public APIs"

PREFERRED: Load rules from external file

read:

  • CONVENTIONS.md
  • docs/architecture.md
  • .editorconfig

Files to always include in chat (pre-added to context)

file:

  • src/types/global.d.ts
  • package.json
  • tsconfig.json

REPOSITORY MAP

Tokens allocated to repository map (0 to disable)

map-tokens: 1024

When to refresh map

map-refresh: auto # Options: auto, always, files, manual

Multiplier when no files specified

map-multiplier-no-files: 2

GIT INTEGRATION

Auto-commit LLM changes

auto-commits: false

Allow commits when repo is dirty

dirty-commits: true

Attribution in commits

attribute-author: true # Git author name
attribute-committer: true # Git committer name
attribute-commit-message-author: false # Prefix with 'aider:'
attribute-commit-message-committer: false # Prefix all commits
attribute-co-authored-by: true # Use Co-authored-by trailer (takes precedence)

Custom commit message prompt

commit-prompt: "Write a concise commit message following Conventional Commits format"

Commit message language

commit-language: en

Skip pre-commit hooks

git-commit-verify: false

LINTING & TESTING

Auto-lint after changes

auto-lint: true

Lint commands by file type (quoted for multi-word commands)

lint-cmd:

  • "python: ruff check --fix"
  • "javascript: eslint --fix"
  • "typescript: eslint --fix"

Auto-run tests after changes

auto-test: false

Test command

test-cmd: "pnpm test"

FILE MANAGEMENT

Aider ignore file

aiderignore: .aiderignore

Add gitignored files to editing scope

add-gitignore-files: false

Only consider files in current subtree

subtree-only: false

HISTORY & CACHING

Input history file

input-history-file: .aider.input.history

Chat history file

chat-history-file: .aider.chat.history.md

LLM conversation history (debugging)

llm-history-file: .aider.llm.history

Restore previous session

restore-chat-history: false

Max chat history before summarization

max-chat-history-tokens: 2048

Prompt caching (Anthropic models)

cache-prompts: true

Keep cache warm with pings (N pings, 5 min intervals)

cache-keepalive-pings: 12 # 12 pings = 60 minutes

OUTPUT & DISPLAY

Color scheme

dark-mode: true

Colorized output

pretty: true

Stream responses

stream: true

Show diffs when committing

show-diffs: false

Custom colors (hex codes)

user-input-color: "#00cc00"
tool-output-color: "#808080"
tool-error-color: "#FF2222"
assistant-output-color: "#0088ff"

Code theme (Pygments style)

code-theme: monokai

VOICE INPUT (Optional)

Voice format

voice-format: wav # Options: wav, webm, mp3

Voice language

voice-language: en

WATCH MODE (IDE Integration)

Watch for AI comments in files

watch-files: false

USER EXPERIENCE

Auto-accept all confirmations

yes-always: false

VI editing mode

vim: false

Enhanced input with history

fancy-input: true

Multi-line input

multiline: false

Terminal bell on completion

notifications: false

Custom notification command

notifications-command: "notify-send 'Aider' 'Task complete'"

Suggest shell commands

suggest-shell-commands: true

Detect and offer to add URLs

detect-urls: true

Encoding

encoding: utf-8

Line endings

line-endings: platform # Options: platform, unix, windows

ANALYTICS (Privacy)

Permanently disable analytics

analytics-disable: true

Disable for current session

analytics: false

Log analytics events to file (debugging)

analytics-log: analytics.log

ADVANCED

Environment file

env-file: .env

Execute commands from file on launch

load: startup.txt

Debugging

verbose: false
show-repo-map: false
show-prompts: false
dry-run: false

Exit after startup (testing)

exit: false

Skip sanity check of repository

skip-sanity-check-repo: false

Check for updates on launch

check-update: true

Show release notes on first run

show-release-notes: true


#### **4.4.2 Rules Array vs CONVENTIONS.md**

Aider supports two approaches for project-specific guidelines:

**Approach 1: Inline Rules (Quick and Simple)**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

model: claude-3-5-sonnet-20241022

rules:

  • "Use TypeScript strict mode"
  • "Prefer async/await over .then()"
  • "Always include error handling"
  • "Add tests for new features"

**Pros:**
- Quick setup
- Config-only (no additional files)
- Good for 3-5 high-level rules

**Cons:**
- Limited space (YAML gets unwieldy)
- No rich formatting (code examples, tables)
- Hard to maintain as project grows

**Approach 2: External Conventions File (Recommended)**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

model: claude-3-5-sonnet-20241022

read:

  • CONVENTIONS.md
  • docs/architecture.md

Enter fullscreen mode Exit fullscreen mode


markdown

Project Coding Conventions

TypeScript Standards

Type Safety

All functions must have explicit return types:

// ✅ CORRECT
function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ WRONG - implicit return type
function calculateTotal(items: Item[]) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Error Handling

// ✅ CORRECT - explicit handling
async function fetchData(): Promise<Result<Data>> {
  try {
    const response = await api.get('/data');
    return { success: true, data: response.data };
  } catch (error) {
    logger.error('API fetch failed', { error });
    return { success: false, error: 'Failed to fetch data' };
  }
}

// ❌ WRONG - silent failure
async function fetchData() {
  try {
    return await api.get('/data');
  } catch {
    return null; // Silent failure!
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing Requirements

Every new feature must include:

  1. Unit tests (Vitest)
  2. Integration tests (if touching API)
  3. E2E test (if user-facing)

Minimum coverage: 80% for business logic.

Commit Message Format

Follow Conventional Commits:

type(scope): description

feat(auth): add password reset flow
fix(api): handle null user in profile endpoint
docs(readme): update installation instructions
Enter fullscreen mode Exit fullscreen mode

Types: feat, fix, docs, style, refactor, test, chore


**Pros:**
- **Rich formatting**: Markdown supports code blocks, tables, lists, headers
- **Detailed examples**: Show both good and bad patterns
- **Maintainable**: Easier to edit than YAML
- **Cached**: Aider caches conventions file, efficient token usage
- **Versionable**: Track changes in git with meaningful diffs

**Cons:**
- Requires separate file
- Can grow large (but that's also a pro—more detail)

**Best Practice: Hybrid Approach**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

Short, high-priority rules inline

rules:

  • "NEVER commit secrets or API keys"
  • "ALWAYS run pnpm lint before committing"

Detailed conventions in external file

read:

  • CONVENTIONS.md

#### **4.4.3 Model Configuration and Aliases**

**Multi-Model Strategy:**

Enter fullscreen mode Exit fullscreen mode


yaml

Main models

model: claude-3-5-sonnet-20241022 # Primary coding (most capable)
weak-model: gpt-4o-mini # Commit messages, summaries (cheap)
editor-model: gpt-4o # Architect mode editing (balanced)

Model aliases for quick switching

alias:

  • "sonnet:claude-3-5-sonnet-20241022"
  • "opus:claude-3-opus-20240229"
  • "gpt4:gpt-4o"
  • "fast:gpt-4o-mini"
  • "local:ollama/deepseek-coder:6.7b"

Cost optimization: Use cheap model for routine tasks

weak-model: gpt-4o-mini # $0.15/1M tokens vs $3/1M for GPT-4o


**Using Aliases:**

Enter fullscreen mode Exit fullscreen mode


bash

Switch models on the fly

aider --model sonnet
aider --model fast # Use for quick tasks
aider --model local # Use local model (no API costs)


**Advanced Model Settings (`.aider.model.settings.yml`):**

For custom or unknown models, create a separate model settings file:

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.model.settings.yml

  • name: openrouter/qwen/qwen2.5-coder-32b-instruct
    edit_format: diff
    weak_model_name: openrouter/qwen/qwen2.5-coder-32b-instruct
    use_repo_map: true
    editor_model_name: openrouter/anthropic/claude-3.7-sonnet
    editor_edit_format: editor-diff

  • name: ollama/deepseek-coder
    edit_format: whole # Local models often better with whole-file edits
    use_repo_map: false # Disable repo map (smaller context)
    send_undo_reply: false

  • name: azure/gpt-4o
    edit_format: diff
    use_repo_map: true
    max_chat_history_tokens: 4096


Reference in main config:

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

model-settings-file: .aider.model.settings.yml
model: openrouter/qwen/qwen2.5-coder-32b-instruct


#### **4.4.4 Production Configurations by Use Case**

**Use Case 1: Solo Developer (Cost-Conscious)**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml - Solo dev optimizing for cost

model: gpt-4o-mini # Cheapest capable model
weak-model: gpt-3.5-turbo # Even cheaper for summaries

Minimal features to reduce API calls

auto-commits: false # Manual review
auto-lint: false # Lint manually
auto-test: false # Test manually
map-tokens: 512 # Smaller repo map

Cache aggressively

cache-prompts: true
cache-keepalive-pings: 12

Show diffs for manual review

show-diffs: true

Rules

read:

  • CONVENTIONS.md

Analytics

analytics-disable: true


**Use Case 2: Small Team (2-5 devs)**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml - Small team collaboration

model: claude-3-5-sonnet-20241022 # Best quality
weak-model: gpt-4o-mini # Cost-effective summaries

Team conventions

read:

  • CONVENTIONS.md
  • docs/architecture.md

Auto-quality checks

auto-lint: true
lint-cmd:

  • "typescript: eslint --fix"
  • "python: ruff check --fix"

Git attribution for team visibility

auto-commits: false # Review before commit
attribute-co-authored-by: true # Show Aider helped

Pre-load shared types

file:

  • src/types/global.d.ts
  • package.json

Shared ignore patterns

aiderignore: .aiderignore

Cache for efficiency

cache-prompts: true

analytics-disable: true


**`.aiderignore` (shared with team):**

Enter fullscreen mode Exit fullscreen mode


gitignore

.aiderignore - Exclude from Aider context

Dependencies

node_modules/
venv/
.venv/
pycache/

Build outputs

dist/
build/
out/
.next/
target/

IDE files

.vscode/
.idea/
*.swp

Logs

*.log
logs/

Large data files

*.csv
*.json.gz
data/

Generated code

src/generated/

Test coverage

coverage/
.coverage


**Use Case 3: Advanced Multi-Model Setup**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml - Power user with multiple models

Model selection

model: deepseek/deepseek-reasoner # Best for complex reasoning
weak-model: gpt-4o-mini # Fast summaries
editor-model: claude-3-5-sonnet-20241022 # Balanced for refactoring

Aliases for quick switching

alias:

  • "r1:deepseek/deepseek-reasoner"
  • "sonnet:claude-3-5-sonnet-20241022"
  • "fast:gpt-4o-mini"
  • "local:ollama/qwen2.5-coder"

Architect mode for complex changes

architect: false # Enable manually when needed
auto-accept-architect: true
editor-edit-format: editor-diff

Repository context

map-tokens: 2048
map-refresh: auto

Aggressive caching (Anthropic)

cache-prompts: true
cache-keepalive-pings: 12

Files pre-loaded

read:

  • CONVENTIONS.md
  • docs/project-context.md

file:

  • src/types/global.d.ts
  • package.json
  • tsconfig.json

Quality automation

auto-lint: true
lint-cmd:

  • "python: ruff check --fix --select I,F,E,W"
  • "javascript: prettier --write"
  • "typescript: eslint --fix"

auto-test: false # Run tests manually for complex changes

Git configuration

auto-commits: false
show-diffs: true
attribute-co-authored-by: true

History

restore-chat-history: false
max-chat-history-tokens: 4096

Display

dark-mode: true
code-theme: monokai
stream: true
fancy-input: true

Privacy

analytics-disable: true


**Model Settings for DeepSeek:**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.model.settings.yml

  • name: deepseek/deepseek-reasoner edit_format: diff use_repo_map: true use_reasoning: true # DeepSeek-specific thinking_tokens: 8000 # Budget for reasoning

**Use Case 4: Enterprise Team (50+ devs)**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml - Enterprise configuration

model: claude-3-5-sonnet-20241022
weak-model: gpt-4o-mini

Organization-wide conventions

read:

  • CONVENTIONS.md # Team standards
  • docs/architecture.md # System design
  • docs/security-policy.md # Security requirements
  • docs/compliance.md # GDPR, SOC2, etc.

Strict quality gates

auto-lint: true
lint-cmd:

  • "typescript: eslint --fix --max-warnings 0"
  • "python: ruff check --fix"

auto-test: false # Manual gate for production code

Git requirements

auto-commits: false # Always require human review
attribute-co-authored-by: true # Audit trail
commit-prompt: "Generate commit message following company standard: type(scope): description. Include ticket reference."

File restrictions

aiderignore: .aiderignore # Comprehensive exclusions
add-gitignore-files: false # Never access sensitive files

Repository map for large codebase

map-tokens: 2048
subtree-only: false # Allow full codebase awareness

Caching for efficiency

cache-prompts: true

Compliance

analytics-disable: true
llm-history-file: null # Don't log LLM conversations (privacy)

Notifications for long-running tasks

notifications: true
notifications-command: "notify-send 'Aider' 'Task complete'"


---

### **4.5 Continue.dev Configuration**

Continue.dev pioneered the **hybrid YAML + Markdown** approach, where structured settings (models, tools, contexts) live in `config.yaml` while natural language instructions use `.continue/rules/*.md` files.

#### **4.5.1 YAML Config vs Markdown Rules Dichotomy**

**The Philosophy:**

- **YAML (`config.yaml`)**: Machine-readable configuration (models, API keys, context providers, tool settings)
- **Markdown (`.continue/rules/*.md`)**: Human-readable instructions (coding standards, patterns, conventions)

**Why the Split:**

| Aspect | YAML Config | Markdown Rules |
|--------|-------------|----------------|
| **Purpose** | Configure Continue's behavior | Guide AI's coding decisions |
| **Audience** | Continue.dev software | Language model |
| **Validation** | JSON Schema enforced | Freeform, no validation |
| **Content** | Structured data (key-value pairs) | Natural language + examples |
| **Changes** | Rare (model switching, provider setup) | Frequent (evolving standards) |
| **Git Strategy** | Commit `.vscode/settings.json` reference | Commit all rule files |

#### **4.5.2 Model Configuration with Roles**

**`config.yaml` Structure:**

Enter fullscreen mode Exit fullscreen mode


yaml

~/.continue/config.yaml (Global)

OR

.continue/config.yaml (Project-specific)

name: my-dev-config
version: 0.0.1
schema: v1

MODELS

models:
# Primary chat model

  • name: Claude 3.5 Sonnet
    provider: anthropic
    model: claude-3-5-sonnet-20241022
    apiKey: ${{ secrets.ANTHROPIC_API_KEY }}
    roles:

    • chat
    • edit
    • apply

    Model-specific options

    defaultCompletionOptions:
    temperature: 0.7
    maxTokens: 4000
    topP: 0.9

    Custom system messages per mode

    chatOptions:
    baseSystemMessage: "You are an expert TypeScript engineer focused on clean, maintainable code."
    baseAgentSystemMessage: "You are systematic and methodical. Break down complex problems into clear steps."
    basePlanSystemMessage: "Create actionable, concrete plans with specific file changes."

    Manually specify capabilities

    capabilities:

    • tool_use
    • image_input

    Request customization

    requestOptions:
    headers:
    X-Custom-Header: "value"

# Fast model for quick tasks

  • name: GPT-4o Mini
    provider: openai
    model: gpt-4o-mini
    apiKey: ${{ secrets.OPENAI_API_KEY }}
    roles:

    • autocomplete

    defaultCompletionOptions:
    temperature: 0.3
    maxTokens: 1000

# Local model (no API costs)

  • name: Qwen Coder Local
    provider: ollama
    model: qwen2.5-coder:7b
    roles:

    • autocomplete

    defaultCompletionOptions:
    temperature: 0.2

CONTEXT PROVIDERS

context:
# Always-available contexts

  • provider: code # Currently open files

  • provider: codebase # Semantic search across codebase
    params:
    nRetrieve: 30 # Retrieve 30 chunks
    nFinal: 5 # Show top 5 in context

  • provider: docs # Fetch from documentation

  • provider: diff # Git diff of unstaged changes

  • provider: terminal # Recent terminal output

  • provider: problems # IDE error/warning messages

  • provider: folder # Directory tree
    params:
    folders:
    - src
    - tests

PROMPTS (Custom Commands)

prompts:

  • name: review
    description: Comprehensive code review
    prompt: |
    Review this code for:

    • Security vulnerabilities
    • Performance issues
    • Code quality and maintainability
    • Test coverage gaps

    Provide specific, actionable feedback.

  • name: test
    description: Generate comprehensive tests
    prompt: |
    Generate tests for this code:

    1. Happy path test
    2. Error handling test
    3. Edge case tests

    Use Vitest and Testing Library.

  • name: optimize
    description: Optimize for performance
    prompt: |
    Analyze this code for performance bottlenecks.
    Suggest specific optimizations with benchmarks.


**Role Types Explained:**

| Role | Purpose | When Active | Model Choice |
|------|---------|-------------|--------------|
| **chat** | Main conversational coding | Chat panel interactions | Most capable model (Claude, GPT-4o) |
| **edit** | Code transformations/refactoring | Edit commands, inline edits | Balanced model (Claude, GPT-4o) |
| **apply** | Targeted code modifications | Applying suggestions | Fast, accurate (Claude, GPT-4o-mini) |
| **autocomplete** | Real-time code suggestions | While typing | Very fast model (GPT-4o-mini, local) |
| **embed** | Semantic search embeddings | Codebase context retrieval | Embedding model (OpenAI text-embedding) |
| **rerank** | Search result ordering | Refining codebase search | Reranking model (Cohere rerank) |
| **summarize** | Content summarization | Summarizing files/changes | Cheap, fast model (GPT-4o-mini) |

**Best Practice: Role Assignment Strategy**

Enter fullscreen mode Exit fullscreen mode


yaml
models:
# Powerful, expensive: Use for complex reasoning

  • name: Claude 3.5 Sonnet provider: anthropic model: claude-3-5-sonnet-20241022 roles: [chat, edit, apply]

# Fast, cheap: Use for autocomplete and summaries

  • name: GPT-4o Mini provider: openai model: gpt-4o-mini roles: [autocomplete, summarize]

# Specialized: Embedding for semantic search

  • name: OpenAI Embeddings provider: openai model: text-embedding-3-small roles: [embed]

#### **4.5.3 Three Rule Approaches Compared**

**Approach 1: YAML `rules` Array (Inline)**

Enter fullscreen mode Exit fullscreen mode


yaml

config.yaml

rules:

  • "Always use TypeScript strict mode"
  • "Prefer functional programming patterns"
  • "Include error handling in all async functions"
  • "Write tests for new features"

**Pros:**
- Simple, all-in-one config
- No additional files
- Good for 3-5 universal rules

**Cons:**
- No rich formatting (code examples, tables)
- Gets messy beyond 10 rules
- Hard to maintain in YAML
- Always loaded (token overhead)

---

**Approach 2: Markdown Rules (`.continue/rules/*.md`)**

Enter fullscreen mode Exit fullscreen mode


markdown


name: TypeScript Standards
description: Type safety and coding patterns for TypeScript
globs: "*/.{ts,tsx}"
alwaysApply: false

tags: [typescript, standards]

TypeScript Coding Standards

Type Safety

Explicit Return Types

// ✅ CORRECT
function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ WRONG
function calculateTotal(items: Item[]) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Avoid any

// ✅ Use `unknown` and type guards
function processData(data: unknown) {
  if (typeof data === 'object' && data !== null) {
    // Type narrowed, now safe to use
  }
}

// ❌ Never use `any`
function processData(data: any) {
  return data.someProperty; // No type safety
}
Enter fullscreen mode Exit fullscreen mode

Async Patterns

Always use async/await:

// ✅ CORRECT
async function fetchUser(id: string): Promise<User> {
  try {
    const response = await api.get(`/users/${id}`);
    return UserSchema.parse(response.data);
  } catch (error) {
    logger.error('Fetch failed', { id, error });
    throw new AppError('User fetch failed', 500);
  }
}

// ❌ AVOID Promise chains
function fetchUser(id: string) {
  return api.get(`/users/${id}`)
    .then(response => response.data)
    .catch(error => console.log(error)); // Bad error handling
}
Enter fullscreen mode Exit fullscreen mode

**YAML Frontmatter Fields:**

| Field | Purpose | Example |
|-------|---------|---------|
| `name` | Human-readable rule name | "TypeScript Standards" |
| `description` | Explains when to use | "Apply when working with TypeScript files" |
| `globs` | File patterns for auto-application | `"**/*.{ts,tsx}"` |
| `alwaysApply` | Apply to all contexts | `true` (default: false) |
| `tags` | Categorization | `["typescript", "standards"]` |
| `regex` | Pattern matching | `".*Controller\\.ts$"` |

**Pros:**
- Rich Markdown formatting
- Code examples with syntax highlighting
- Conditional loading (globs)
- Separate concerns (one file per topic)
- Easy to maintain and version

**Cons:**
- Multiple files to manage
- Need to understand frontmatter
- Requires directory structure

---

**Approach 3: `chatOptions.baseSystemMessage` (Model-Specific Override)**

Enter fullscreen mode Exit fullscreen mode


yaml
models:

  • name: Claude 3.5 Sonnet
    provider: anthropic
    model: claude-3-5-sonnet-20241022

    Override default system messages

    chatOptions:
    baseSystemMessage: |
    You are an expert Go developer specializing in microservices.

    Always follow these principles:
    - Use interfaces for dependency injection
    - Error handling with explicit error returns
    - Context for cancellation and timeouts
    - Structured logging with slog
    

    baseAgentSystemMessage: |
    When in Agent mode:
    1. Break problems into clear steps
    2. Verify preconditions before acting
    3. Provide status updates

    basePlanSystemMessage: |
    When planning:
    - List specific files to modify
    - Outline changes for each file
    - Consider dependencies and ordering


**Pros:**
- Model-specific customization
- Overrides Continue's defaults completely
- Good for language-specific setups (Go, Rust, etc.)

**Cons:**
- Buried in YAML (less visible)
- No rich formatting
- Applies to ALL interactions with that model
- Not file-specific

---

**Decision Matrix: Which Approach to Use?**

| Scenario | Recommended Approach |
|----------|---------------------|
| **3-5 universal rules, single language** | YAML `rules` array |
| **Multiple languages, file-type specific rules** | Markdown rules with `globs` |
| **Language-specific model (e.g., Rust assistant)** | `chatOptions.baseSystemMessage` |
| **Team collaboration, evolving standards** | Markdown rules (easy to review) |
| **Large project, 10+ rule categories** | Multiple Markdown files |
| **Mode-specific behavior (Agent vs Chat)** | `chatOptions.base*SystemMessage` |
| **Combination of all above** | Hybrid: YAML + Markdown + chatOptions |

**Hybrid Example (Recommended for Most Projects):**

Enter fullscreen mode Exit fullscreen mode


yaml

config.yaml

Universal short rules

rules:

  • "NEVER commit secrets or API keys"
  • "ALWAYS run linter before committing"

Markdown rules for detailed guidance

(rules loaded automatically from .continue/rules/)

models:

  • name: Claude 3.5 Sonnet
    provider: anthropic
    model: claude-3-5-sonnet-20241022

    Override for mode-specific behavior

    chatOptions:
    baseAgentSystemMessage: "Break complex tasks into atomic steps. Verify preconditions."


Enter fullscreen mode Exit fullscreen mode

.continue/
├── config.yaml # Model and tool config
└── rules/
├── 01-typescript.md # globs: */.{ts,tsx}
├── 02-react.md # globs: */.{tsx,jsx}
├── 03-python.md # globs: */.py
├── 04-testing.md # Manual invocation
└── 05-security.md # alwaysApply: true


#### **4.5.4 Rule Loading Order and Precedence**

Continue.dev loads rules in this hierarchy:

**Loading Order (First to Last):**

1. **Hub assistant rules** (if using Continue Hub cloud config)
2. **Referenced Hub rules** (via `uses:` in config.yaml)
3. **Local workspace rules** (`.continue/rules/`)
4. **Global user rules** (`~/.continue/rules/`)

**Important**: Later rules DON'T override earlier ones—they're **cumulative** (all applicable rules are included).

**Example Loading Scenario:**

Enter fullscreen mode Exit fullscreen mode

Hub configuration (if logged in)

Hub Assistant: "React Development Assistant"
└── Includes Hub rules: @continuedev/react-best-practices

Project config.yaml

uses:

  • continuedev/security-standards # Referenced Hub rule

Project rules

.continue/rules/
├── typescript-standards.md # Local project rule
└── company-conventions.md # Local project rule

Global user rules

~/.continue/rules/
└── personal-preferences.md # Your global preferences


**Loaded Context (cumulative):**
1. Hub: React best practices
2. Hub: Security standards
3. Local: TypeScript standards
4. Local: Company conventions
5. Global: Personal preferences

**All five are active simultaneously** (assuming `alwaysApply: true` or matching `globs`).

**Controlling Precedence:**

Since rules are cumulative, use **explicit override language** when needed:

Enter fullscreen mode Exit fullscreen mode


markdown


name: Company Convention Overrides

alwaysApply: true

Company-Specific Overrides

IMPORTANT: These rules OVERRIDE generic best practices.

State Management

Despite general React best practices recommending Context API,
our company standard is:

  • ✅ USE: Redux Toolkit for ALL global state
  • ❌ AVOID: Context API, Zustand, Jotai

Rationale: Existing codebase, team expertise, debugging tools.


#### **4.5.5 Known Issues and Workarounds**

**Issue 1: Rules Not Applied Without `alwaysApply: true`**

**Symptom**: Rule file exists but AI doesn't follow it

**Cause**: Bug in Continue.dev v0.9.x - `description` and `globs` fields don't reliably trigger rule application

**Workarounds:**

1. **Set `alwaysApply: true`** (simplest):
Enter fullscreen mode Exit fullscreen mode

markdown

name: TypeScript Standards

alwaysApply: true


2. **Omit frontmatter entirely** (fallback):
Enter fullscreen mode Exit fullscreen mode


markdown

TypeScript Standards

Rules content here...


3. **Manually reference in chat**:
Enter fullscreen mode Exit fullscreen mode

@.continue/rules/typescript-standards.md


**Tracking**: GitHub issue #5817 (as of May 2025)

---

**Issue 2: Schema Loading Issues After Extension Update**

**Symptom**: VS Code shows "Unknown property" warnings in `config.yaml`

**Cause**: Extension update changed schema path reference

**Solution:**

1. **Update VS Code settings**:
Enter fullscreen mode Exit fullscreen mode


json
// .vscode/settings.json
{
"yaml.schemas": {
"https://continue.dev/schema/config.json": ".continue/config.yaml"
}
}


2. **Or reinstall Continue extension**:
   - Uninstall Continue.dev
   - Reload VS Code
   - Reinstall Continue.dev

---

**Issue 3: Hub vs Local Rule Confusion**

**Symptom**: Local rules don't appear when using Hub configs

**Cause**: Hub configurations require explicit `uses:` references

**Solution**:

Either:

**A) Don't use Hub configs** (use local only):
Enter fullscreen mode Exit fullscreen mode


yaml

config.yaml

name: My Local Config
version: 0.0.1

models: [...] # Define models locally

Rules automatically loaded from .continue/rules/


**B) Explicitly reference local rules in Hub config**:
Enter fullscreen mode Exit fullscreen mode


yaml

config.yaml (with Hub)

name: My Hub Config

models:

  • uses: anthropic/claude-sonnet-4 # Hub model

rules:

  • uses: ./blocks/typescript-standards.md # Local rule file

---

**Issue 4: Token Limit Exceeded with Too Many Rules**

**Symptom**: Errors about context length, slow responses

**Cause**: Too many `alwaysApply: true` rules loaded simultaneously

**Solution: Be Strategic with `alwaysApply`**

Enter fullscreen mode Exit fullscreen mode


markdown


name: React Patterns
globs: "*/.{tsx,jsx}"

alwaysApply: false


name: React Patterns

alwaysApply: true


**Rule of Thumb:**
- **1-3 rules**: `alwaysApply: true` (core standards)
- **5-10 rules**: Use `globs` for conditional loading
- **10+ rules**: Multiple files with narrow globs

#### **4.5.6 Production Example: Full-Stack TypeScript Project**

Enter fullscreen mode Exit fullscreen mode


yaml

.continue/config.yaml

name: fullstack-typescript-config
version: 1.0.0
schema: v1

MODELS

models:
# Primary: Claude for complex reasoning

  • name: Claude 3.5 Sonnet
    provider: anthropic
    model: claude-3-5-sonnet-20241022
    apiKey: ${{ secrets.ANTHROPIC_API_KEY }}
    roles: [chat, edit, apply]

    defaultCompletionOptions:
    temperature: 0.7
    maxTokens: 4000

    chatOptions:
    baseSystemMessage: |
    You are an expert full-stack TypeScript engineer.
    Focus on type safety, performance, and maintainability.
    Always provide working, production-ready code.

# Fast: GPT-4o Mini for autocomplete

  • name: GPT-4o Mini
    provider: openai
    model: gpt-4o-mini
    apiKey: ${{ secrets.OPENAI_API_KEY }}
    roles: [autocomplete, summarize]

    defaultCompletionOptions:
    temperature: 0.3
    maxTokens: 1000

CONTEXT

context:

  • provider: code

  • provider: codebase
    params:
    nRetrieve: 30
    nFinal: 5

  • provider: docs

  • provider: diff

  • provider: terminal

CUSTOM PROMPTS

prompts:

  • name: test
    description: Generate comprehensive tests
    prompt: |
    Generate tests for this code using Vitest and Testing Library.
    Include:

    1. Happy path test
    2. Error handling test
    3. Edge cases

    Achieve >90% coverage.

  • name: optimize
    description: Performance optimization review
    prompt: |
    Analyze this code for performance issues:

    • O(n²) or worse algorithms
    • Unnecessary re-renders (React)
    • Memory leaks
    • Bundle size impact

    Suggest specific optimizations with benchmarks.

SHORT RULES

rules:

  • "NEVER commit secrets or API keys"
  • "ALWAYS run 'pnpm lint' before committing"
  • "USE pnpm, NOT npm or yarn"

**Rule Files:**

Enter fullscreen mode Exit fullscreen mode

.continue/
├── config.yaml
└── rules/
├── 01-project-overview.md
├── 02-typescript-standards.md
├── 03-react-patterns.md
├── 04-backend-api.md
├── 05-testing-guide.md
└── 06-security-checklist.md


**`01-project-overview.md` (Always Applied):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: Project Overview
description: Core project context and architecture

alwaysApply: true

Project: E-Commerce Platform

Tech Stack

  • Frontend: Next.js 15, React 19, TypeScript 5.4, Tailwind CSS
  • Backend: tRPC 11, Drizzle ORM, PostgreSQL 16
  • Monorepo: Turborepo
  • Deployment: Vercel

Architecture

apps/
├── web/              # Next.js frontend
└── api/              # Standalone API (future)
packages/
├── ui/               # Shared components
├── database/         # Drizzle schema
└── types/            # Shared types
Enter fullscreen mode Exit fullscreen mode

Key Principles

  • Server Components by default
  • tRPC for type-safe APIs
  • Zod for validation
  • TanStack Query for data fetching

**`02-typescript-standards.md` (Auto-Attached):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: TypeScript Standards
description: Type safety and patterns
globs: "*/.{ts,tsx}"

alwaysApply: false

TypeScript Standards

Type Annotations

// ✅ Explicit return types
function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ No implicit return types
function calculateTotal(items: Item[]) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Error Handling

// ✅ Result type pattern
type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

async function fetchData(): Promise<Result<Data>> {
  try {
    const data = await api.get('/data');
    return { success: true, data };
  } catch (error) {
    logger.error('API error', { error });
    return { success: false, error: 'Failed to fetch' };
  }
}
Enter fullscreen mode Exit fullscreen mode

Zod Schemas

import { z } from 'zod';

// Define schema
const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  name: z.string().min(2),
});

// Infer TypeScript type
type User = z.infer<typeof UserSchema>;

// Validate at runtime
const user = UserSchema.parse(untrustedData);
Enter fullscreen mode Exit fullscreen mode

**`03-react-patterns.md` (Auto-Attached to TSX):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: React Patterns
description: Component and state management patterns
globs: "*/.{tsx,jsx}"

alwaysApply: false

React Patterns

Server vs Client Components

Default: Server Components

// ✅ Server Component (no directive needed)
async function UserProfile({ userId }: { userId: string }) {
  const user = await db.query.users.findFirst({
    where: eq(users.id, userId)
  });

  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Client Components (when needed)

'use client';

// Only add 'use client' when:
// - Using hooks (useState, useEffect, etc.)
// - Using browser APIs
// - Event handlers

export function InteractiveButton() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Enter fullscreen mode Exit fullscreen mode

State Management

Use Case Solution
Server data TanStack Query
Form state React Hook Form + Zod
Global client state Zustand
Local state useState
URL state useSearchParams

Component Size

  • Max 200 lines per component
  • If exceeded: Extract sub-components
  • Composition over props drilling
// ✅ Composition
<Card>
  <CardHeader>
    <CardTitle>{title}</CardTitle>
  </CardHeader>
  <CardContent>{content}</CardContent>
</Card>

// ❌ Props drilling
<Card 
  title={title}
  content={content}
  headerStyle={{...}}
  contentStyle={{...}}
/>
Enter fullscreen mode Exit fullscreen mode

**`04-backend-api.md` (Auto-Attached to API files):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: Backend API Patterns
description: tRPC procedures and database patterns
globs: "lib/api/*/"

alwaysApply: false

Backend API Patterns

tRPC Procedure Structure

import { z } from 'zod';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '@/lib/api/trpc';

export const userRouter = createTRPCRouter({
  // Public procedure
  getById: publicProcedure
    .input(z.object({ id: z.string().uuid() }))
    .query(async ({ input, ctx }) => {
      const user = await ctx.db.query.users.findFirst({
        where: eq(users.id, input.id)
      });

      if (!user) {
        throw new TRPCError({
          code: 'NOT_FOUND',
          message: 'User not found',
        });
      }

      return user;
    }),

  // Protected procedure (requires auth)
  update: protectedProcedure
    .input(z.object({
      id: z.string().uuid(),
      name: z.string().min(2).optional(),
      email: z.string().email().optional(),
    }))
    .mutation(async ({ input, ctx }) => {
      // ctx.user is available (from protectedProcedure)
      if (ctx.user.id !== input.id) {
        throw new TRPCError({
          code: 'FORBIDDEN',
          message: 'Cannot update other users',
        });
      }

      const updated = await ctx.db
        .update(users)
        .set(input)
        .where(eq(users.id, input.id))
        .returning();

      return updated[0];
    }),
});
Enter fullscreen mode Exit fullscreen mode

Database Patterns (Drizzle)

Queries

// ✅ Eager loading with relations
const users = await db.query.users.findMany({
  with: {
    posts: true,
    profile: true,
  },
});

// ❌ N+1 queries
const users = await db.query.users.findMany();
for (const user of users) {
  user.posts = await db.query.posts.findMany({
    where: eq(posts.userId, user.id)
  });
}
Enter fullscreen mode Exit fullscreen mode

Transactions

// ✅ Atomic multi-step operations
await db.transaction(async (tx) => {
  const user = await tx.insert(users).values(userData).returning();
  await tx.insert(profiles).values({
    userId: user[0].id,
    ...profileData
  });
});
Enter fullscreen mode Exit fullscreen mode

Error Handling

import { TRPCError } from '@trpc/server';

// Standard TRPC errors
throw new TRPCError({
  code: 'NOT_FOUND',        // 404
  message: 'Resource not found',
});

throw new TRPCError({
  code: 'FORBIDDEN',        // 403
  message: 'Insufficient permissions',
});

throw new TRPCError({
  code: 'BAD_REQUEST',      // 400
  message: 'Invalid input',
});

throw new TRPCError({
  code: 'INTERNAL_SERVER_ERROR',  // 500
  message: 'Unexpected error',
});
Enter fullscreen mode Exit fullscreen mode

**`05-testing-guide.md` (Manual):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: Testing Guide
description: Comprehensive testing patterns and requirements

alwaysApply: false

Testing Guide

Invoke with: @.continue/rules/testing-guide.md

Test Structure (AAA Pattern)

import { describe, it, expect, beforeEach } from 'vitest';

describe('UserService', () => {
  let service: UserService;

  beforeEach(() => {
    // ARRANGE: Set up test environment
    service = new UserService(mockDb);
  });

  it('creates user with valid data', async () => {
    // ARRANGE: Prepare data
    const userData = { email: 'test@example.com', name: 'Test' };

    // ACT: Execute function
    const result = await service.createUser(userData);

    // ASSERT: Verify outcome
    expect(result.success).toBe(true);
    expect(result.data).toMatchObject(userData);
  });
});
Enter fullscreen mode Exit fullscreen mode

Coverage Requirements

  • Unit: 80% minimum
  • Integration: 70% minimum
  • E2E: Critical paths only

Mocking with MSW

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  rest.get('https://api.example.com/users', (req, res, ctx) => {
    return res(ctx.json([{ id: '1', name: 'User 1' }]));
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Enter fullscreen mode Exit fullscreen mode

**`06-security-checklist.md` (Always Applied):**

Enter fullscreen mode Exit fullscreen mode

markdown

name: Security Checklist
description: Security requirements and common vulnerabilities
alwaysApply: true

tags: [security, compliance]

Security Checklist

Authentication

  • ✅ JWTs in HttpOnly cookies (NEVER localStorage)
  • ✅ Refresh token rotation
  • ✅ CSRF protection on mutations

Input Validation

// ✅ ALWAYS validate with Zod
const input = UserInputSchema.parse(untrustedData);

// ❌ NEVER trust raw input
const user = await createUser(req.body); // Unsafe!
Enter fullscreen mode Exit fullscreen mode

SQL Injection Prevention

// ✅ Parameterized queries (Drizzle ORM)
const users = await db.query.users.findMany({
  where: eq(users.email, email)  // Safe
});

// ❌ String concatenation
const query = `SELECT * FROM users WHERE email = '${email}'`; // SQL injection!
Enter fullscreen mode Exit fullscreen mode

Secrets Management

  • ✅ Environment variables only
  • ✅ Validate with @t3-oss/env-nextjs
  • ❌ NEVER hardcode secrets

Common Vulnerabilities Checklist

  • [ ] XSS: User input sanitized?
  • [ ] SQL Injection: Queries parameterized?
  • [ ] CSRF: State-changing endpoints protected?
  • [ ] Rate Limiting: Public endpoints limited?
  • [ ] Secrets: No hardcoded keys?

---

This comprehensive Continue.dev configuration demonstrates:
1. **Clear separation**: YAML for structure, Markdown for instructions
2. **Role-based models**: Appropriate model for each task
3. **Conditional loading**: Rules apply only when relevant (globs)
4. **Hierarchical organization**: 6 focused rule files vs 1 monolith
5. **Production-ready patterns**: Real-world examples with explanations

---

### **4.6 Cline and Roo-Cline**

Cline and Roo-Cline represent two evolutionary branches: **Cline prioritizes simplicity** with straightforward Markdown rules, while **Roo-Cline adds sophisticated mode-based customization** with YAML configuration and granular tool permissions.

#### **4.6.1 Cline's `.clinerules` System**

**Overview:**
- **Format**: Plain Markdown (no frontmatter, no schema)
- **Locations**: Single file OR directory of multiple files
- **Philosophy**: Simple, human-readable, easy to adopt

**Single File Approach:**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── .clinerules # Single configuration file
├── src/
└── tests/


**`.clinerules` Example:**

Enter fullscreen mode Exit fullscreen mode


markdown

Project Guidelines

Tech Stack

  • Language: TypeScript 5.4
  • Framework: Next.js 15 (App Router)
  • Database: PostgreSQL with Drizzle ORM
  • Testing: Vitest for unit, Playwright for E2E

Documentation Requirements

  • Update /docs when modifying features
  • Keep README.md in sync with capabilities
  • Maintain changelog entries in CHANGELOG.md

Architecture Decision Records (ADRs)

Create ADRs in /docs/adr for:

  • Major dependency changes
  • Architectural pattern changes
  • New integration patterns
  • Database schema changes

Follow template in /docs/adr/template.md

Code Style & Patterns

API Client Generation

  • Generate using OpenAPI Generator
  • Use TypeScript axios template
  • Place generated code in /src/generated
  • DON'T manually edit generated files

Design Patterns

  • Prefer composition over inheritance
  • Use repository pattern for data access
  • Follow error handling pattern in /src/utils/errors.ts

Naming Conventions

  • Variables/Functions: camelCase (getUserById)
  • Types/Interfaces: PascalCase (UserProfile)
  • Constants: UPPER_SNAKE_CASE (MAX_RETRY_COUNT)
  • Files: kebab-case (user-profile.tsx)

Testing Standards

  • Unit tests: Required for business logic
  • Integration tests: Required for API endpoints
  • E2E tests: Required for critical user flows
  • Coverage: Minimum 80% for new features

Test Structure

describe('featureName', () => {
  it('should handle happy path', () => {
    // Arrange
    const input = createTestInput();

    // Act
    const result = performOperation(input);

    // Assert
    expect(result).toBe(expected);
  });

  it('should handle error case', () => {
    // Test error handling
  });
});
Enter fullscreen mode Exit fullscreen mode

Security Requirements

  • NEVER commit secrets or API keys
  • ALWAYS validate user inputs
  • Use parameterized queries (prevent SQL injection)
  • Implement rate limiting on public endpoints

Git Workflow

  • Feature branches: feat/feature-name
  • Commit format: Conventional Commits (feat:, fix:, docs:)
  • PRs require 1 approval + passing CI

Before Deploying

  1. Run full test suite: pnpm test
  2. Check TypeScript: pnpm type-check
  3. Lint: pnpm lint --max-warnings 0
  4. Build succeeds: pnpm build
  5. Environment variables configured in deployment platform

**Directory Approach (Introduced in Cline 3.7.0):**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── .clinerules/
│ ├── 01-project-overview.md
│ ├── 02-coding-standards.md
│ ├── 03-testing-guide.md
│ ├── 04-deployment.md
│ └── current-sprint-focus.md
├── src/
└── tests/


**How It Works:**
- Cline **automatically merges** all Markdown files in `.clinerules/`
- Numeric prefixes (01-, 02-) help organize logical order
- Files are loaded alphabetically (case-insensitive)

**Example: `01-project-overview.md`**

Enter fullscreen mode Exit fullscreen mode


markdown

Project Overview

Product

E-commerce platform for small businesses

Current Sprint (Week of 2025-11-25)

Focus: Implementing shopping cart and checkout flow

Key tasks:

  • [ ] Cart state management (Zustand)
  • [ ] Checkout form with Stripe integration
  • [ ] Order confirmation email

Stack

  • Frontend: Next.js 15 + React 19 + TypeScript
  • Styling: Tailwind CSS + shadcn/ui
  • Backend: tRPC + Drizzle ORM + PostgreSQL
  • Payments: Stripe

Architecture

Feature-sliced design:

src/
├── features/
│   ├── cart/
│   ├── checkout/
│   └── products/
Enter fullscreen mode Exit fullscreen mode

**Example: `02-coding-standards.md`**

Enter fullscreen mode Exit fullscreen mode


markdown

Coding Standards

TypeScript

  • Strict mode enabled
  • Explicit return types on all functions
  • No any types (use unknown + type guards)

React

  • Functional components only
  • Server Components by default
  • Add 'use client' only when needed

Imports

// 1. External dependencies
import { useState } from 'react';
import { z } from 'zod';

// 2. Internal modules
import { Button } from '@/components/ui/button';
import { trpc } from '@/lib/trpc/client';

// 3. Relative imports
import { ProductCard } from './ProductCard';
Enter fullscreen mode Exit fullscreen mode

Error Handling

// ✅ ALWAYS: Explicit try-catch with logging
try {
  await operation();
} catch (error) {
  logger.error('Operation failed', { error });
  throw new AppError('User-friendly message', 500);
}

// ❌ NEVER: Silent failures
try {
  await operation();
} catch {
  // Silent failure!
}
Enter fullscreen mode Exit fullscreen mode

#### **Global Rules (OS-Specific Locations)**

Cline supports **global rules** that apply across ALL projects:

**Locations:**

| OS | Path |
|----|------|
| **Windows** | `Documents\Cline\Rules\` |
| **macOS** | `~/Documents/Cline/Rules/` |
| **Linux/WSL** | `~/Documents/Cline/Rules/` (may fall back to `~/Cline/Rules`) |

**Use Cases:**
- Your personal coding style preferences
- Organization-wide standards (if shared drive)
- Language-specific conventions you always follow

**Example: `~/Documents/Cline/Rules/my-preferences.md`**

Enter fullscreen mode Exit fullscreen mode


markdown

My Personal Coding Preferences

Response Format

  • Give concise answers
  • Show code examples with explanations
  • Highlight breaking changes or gotchas

Code Style

  • Prefer modern ES2022+ syntax
  • Use destructuring where readable
  • Favor explicit over clever

Testing

  • I always write tests AFTER implementation (not TDD)
  • Focus on integration tests over unit tests
  • Mock external APIs, use real database (test database)

Git

  • Commit messages: Conventional Commits format
  • I use feat:, fix:, refactor:, docs:, test:

**Precedence:**
- **Project rules** (`.clinerules` or `.clinerules/`) override global rules
- **Global rules** provide defaults when project rules don't cover something

#### **4.6.2 Rules Bank Strategy**

For developers working across multiple contexts (different clients, project types, frameworks), Cline supports a **rules bank** pattern:

**Directory Structure:**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── .clinerules/ # Active rules (auto-loaded)
│ ├── 01-core.md
│ └── client-a-specifics.md

├── clinerules-bank/ # Inactive rule repository
│ ├── clients/
│ │ ├── client-a.md
│ │ ├── client-b.md
│ │ └── client-c.md
│ ├── frameworks/
│ │ ├── react.md
│ │ ├── vue.md
│ │ └── angular.md
│ └── project-types/
│ ├── api-service.md
│ ├── frontend-app.md
│ └── data-pipeline.md
└── src/


**Workflow:**

**Scenario: Switch from Client A to Client B project**

Enter fullscreen mode Exit fullscreen mode


bash

Remove Client A rules

rm .clinerules/client-a-specifics.md

Add Client B rules

cp clinerules-bank/clients/client-b.md .clinerules/

Or if switching frameworks too:

cp clinerules-bank/frameworks/vue.md .clinerules/


**Scenario: Start new React frontend project**

Enter fullscreen mode Exit fullscreen mode


bash

Copy relevant rules into active directory

cp clinerules-bank/frameworks/react.md .clinerules/02-react.md
cp clinerules-bank/project-types/frontend-app.md .clinerules/03-frontend.md


**Example: `clinerules-bank/clients/client-a.md`**

Enter fullscreen mode Exit fullscreen mode


markdown

Client A Specific Rules

Branding

  • Primary color: #1E40AF (blue-700)
  • Font: Inter for UI, JetBrains Mono for code

Client Preferences

  • Verbose logging (client likes detailed logs)
  • Conservative error handling (prefer graceful degradation)
  • Accessibility: WCAG AA minimum

Deployment

Contact


**Example: `clinerules-bank/frameworks/react.md`**

Enter fullscreen mode Exit fullscreen mode


markdown

React Framework Rules

Component Patterns

  • Functional components with hooks
  • Prefer composition over props drilling
  • Extract custom hooks for reusable logic

State Management

  • Local: useState
  • Global: Context API or Zustand
  • Server: React Query

File Structure

features/
  user-profile/
    UserProfile.tsx
    UserProfile.test.tsx
    useUserProfile.ts
    types.ts
Enter fullscreen mode Exit fullscreen mode

Performance

  • Memoize expensive calculations (useMemo)
  • Memoize callbacks passed to children (useCallback)
  • Lazy load routes: const Route = lazy(() => import('./Route'))

**Benefits:**
- **Context switching**: Quickly adapt to different project requirements
- **Reusability**: Build library of proven patterns
- **Experimentation**: Try different rule sets without losing originals
- **Client work**: Easily switch between client-specific conventions

---

#### **4.6.3 Roo-Cline's Custom Modes Revolution**

**Key Innovation: Mode-Based AI Behavior**

Roo-Cline (fork of Cline) introduces **custom modes**—distinct AI personas with:
- **Specific roles** (Documentation Writer, Security Auditor, Test Engineer)
- **Tool permissions** (read-only, edit with restrictions, command execution)
- **File access control** (regex patterns limiting which files can be modified)
- **Model assignments** (sticky models per mode for cost optimization)

**Configuration Files:**

| File | Purpose | Format |
|------|---------|--------|
| `.roomodes` | Mode definitions | YAML (preferred) or JSON |
| `.roo/rules-{mode-slug}/` | Mode-specific instruction files | Markdown |
| `~/.roo/custom_modes.yaml` | Global modes (all projects) | YAML |

#### **4.6.4 Complete `.roomodes` Schema**

**YAML Format (Recommended):**

Enter fullscreen mode Exit fullscreen mode


yaml
customModes:
# Mode 1: Documentation Writer

  • slug: docs-writer # Unique ID (a-z, 0-9, hyphens only)
    name: 📝 Documentation Writer # Display name (can include emojis)
    description: > # Short summary for mode selector
    Specialized mode for writing and editing technical documentation.
    Focuses on clarity, completeness, and examples.

    roleDefinition: > # AI's identity (prepended to system prompt)
    You are a technical writer specializing in clear, comprehensive documentation.
    Your primary focus is creating accessible documentation with practical examples.
    You excel at explaining complex concepts simply.

    whenToUse: > # For Orchestrator mode delegation
    Use this mode when the task involves writing or editing documentation,
    creating README files, or explaining code functionality.

    customInstructions: |- # Additional guidelines (near end of prompt)
    ## Documentation Standards

    • Use clear, concise language
    • Include code examples for every concept
    • Follow project's documentation style guide
    • Add tables of contents for long documents
    • Use proper Markdown formatting

    groups: # Tool permissions

    • read # Can read any file
    • - edit # Can edit, with restrictions:
      • fileRegex: \.(md|mdx)$ # Only Markdown files description: Markdown files only
    • browser # Can browse web for research

    source: project # 'project' or 'global'

# Mode 2: Security Auditor

  • slug: security-auditor
    name: 🛡️ Security Auditor

    roleDefinition: >
    You are an expert security researcher conducting thorough security audits.
    Focus on identifying high-priority vulnerabilities and providing
    actionable remediation steps.

    customInstructions: |-
    ## Audit Process

    ### 1. ANALYSIS PHASE

    • Review codebase systematically
    • Focus on: authentication, data handling, API endpoints, user input
    • Document concerns with file locations and line numbers

    ### 2. PLANNING PHASE

    • Explain nature and severity of security risks
    • Provide evidence of potential attack vectors
    • Outline remediation steps with priority ordering

    ### 3. IMPLEMENTATION PHASE (if approved)

    • Make minimal necessary changes
    • Document before/after comparisons
    • Verify no new vulnerabilities introduced

    ## Key Focus Areas

    • Exposed credentials and environment variables
    • Insufficient input validation (XSS, SQL injection)
    • Authentication/authorization bypasses
    • Missing rate limiting
    • Insecure dependencies

    ## DO NOT

    • Make cosmetic changes unrelated to security
    • Skip analysis and planning phases
    • Implement fixes without explaining risk first

    groups:

    • read # Read-only for analysis
    • command # Can run security scanners

    source: global

# Mode 3: Test Engineer (TDD Red Phase)

  • slug: tdd-red-phase
    name: 🔴 TDD Red Phase Specialist

    roleDefinition: >
    You are a TDD expert specializing in the Red phase.
    Write failing unit tests based on requirements and specifications.
    Tests must fail due to missing implementation, not setup errors.

    customInstructions: |-
    ### RESTRICTIONS

    • This phase CANNOT modify non-test files
    • ALL tests must fail due to missing SUT (System Under Test) logic
    • Use test inputs designed to fail against SUT stubs

    ### WORKFLOW

    1. Analyze requirements (BDD scenarios, user stories)
    2. Set up test infrastructure (mocks, fixtures)
    3. Write test assertions with guard rails
    4. Verify failure (due to missing logic, not test errors)

    ### QUALITY INDICATORS

    🟢 Excellent (90-100):

    • Tests are reliable and maintainable
    • Clear behavior verification
    • Proper test isolation
    • Descriptive test names

    🟡 Acceptable (70-89):

    • Tests work but could be clearer
    • Some coupling between tests
    • Minor maintainability issues

    🔴 Requires Revision (<70):

    • Significant reliability issues
    • Unclear test purpose
    • Poor isolation
    • Hard to maintain

    groups:

    • read
    • - edit
      • fileRegex: .*.test.(js|tsx?|py)$ description: Test files only
    • command # Can run tests

    source: global

# Mode 4: Code Mode Override (Project-Specific)

  • slug: code # Overrides built-in 'code' mode
    name: 💻 Code (Project Custom)

    roleDefinition: >
    You are a senior TypeScript engineer working on this Next.js project.
    Focus on type safety, performance, and Next.js 15 best practices.

    customInstructions: |-
    ## Project-Specific Rules

    • Use pnpm (NOT npm)
    • Server Components by default
    • Add 'use client' only when necessary
    • tRPC for all API calls
    • Zod for validation
    • Drizzle ORM for database

    ## File Organization

    • Features go in src/features/
    • Shared UI in src/components/ui/
    • Utils in src/lib/

    groups:

    • read
    • - edit
      • fileRegex: .(ts|tsx)$ description: TypeScript files only
    • command

    source: project # Project-specific override


**JSON Format (Alternative, less preferred):**

Enter fullscreen mode Exit fullscreen mode


json
{
"customModes": [{
"slug": "docs-writer",
"name": "📝 Documentation Writer",
"description": "Specialized mode for writing technical documentation.",
"roleDefinition": "You are a technical writer specializing in clear documentation.",
"whenToUse": "Use when writing or editing documentation.",
"customInstructions": "Focus on clarity and examples.",
"groups": [
"read",
["edit", { "fileRegex": "\.(md|mdx)$", "description": "Markdown only" }],
"browser"
],
"source": "project"
}]
}


#### **4.6.5 Tool Permissions and File Regex**

**Available Tools:**

| Tool | Permission | What It Enables |
|------|-----------|----------------|
| `read` | View files | Read any file in workspace |
| `edit` | Modify files | Create, update, delete files |
| `browser` | Web access | Browse URLs, search web |
| `command` | Execute shell | Run terminal commands |
| `mcp` | MCP servers | Access Model Context Protocol servers |

**Permission Syntax:**

**Simple (no restrictions):**
Enter fullscreen mode Exit fullscreen mode


yaml
groups:

  • read
  • edit # Can edit ANY file
  • command

**Restricted (with regex):**
Enter fullscreen mode Exit fullscreen mode


yaml
groups:

  • read
  • - edit # Tuple: [tool, restrictions]
    • fileRegex: \.(md|mdx)$ # Regex pattern description: Markdown files only
  • browser

**Critical: Regex Escaping**

| YAML | JSON Equivalent | Matches |
|------|----------------|---------|
| `\.md$` | `"\\.md$"` | Files ending in `.md` |
| `^src/.*` | `"^src/.*"` | Files in `src/` |
| `\.(css\|scss)$` | `"\\.(css\\|scss)$"` | CSS or SCSS files |
| `^(?!.*(test\|spec)).*\.(js\|ts)$` | `"^(?!.*(test\\|spec)).*\\.(js\\|ts)$"` | JS/TS excluding tests |

**Rules:**
- **YAML**: Single backslash (`\.md$`)
- **JSON**: Double backslash (`\\.md$`)
- **Pattern matches**: Full relative path from workspace root
- **Case sensitive**: By default

**Example Regex Patterns:**

Enter fullscreen mode Exit fullscreen mode


yaml

Documentation Writer: Markdown only

  • - edit
    • fileRegex: .(md|mdx|markdown)$ description: Markdown documentation files

Frontend Dev: React files only

  • - edit
    • fileRegex: .(tsx|jsx)$ description: React component files

Backend Dev: Server-side only

  • - edit
    • fileRegex: (src/api/|src/lib/|src/db/).*.(ts|js)$ description: Backend code only

Test Writer: Test files only

  • - edit
    • fileRegex: .*.(test|spec).(ts|tsx|js|jsx)$ description: Test files only

Config Editor: Config files only

  • - edit
    • fileRegex: (.(json|yaml|yml|toml|env)|^..*rc)$ description: Configuration files

Python Backend: Python files excluding notebooks

  • - edit
    • fileRegex: ^(?!..ipynb$)..py$ description: Python files (no notebooks)

**Security Best Practice:**

Always restrict edit permissions in specialized modes:

Enter fullscreen mode Exit fullscreen mode


yaml

❌ RISKY: Documentation mode can edit code

customModes:

  • slug: docs-writer groups:
    • read
    • edit # Can edit anything!

✅ SAFE: Documentation mode restricted

customModes:

  • slug: docs-writer groups:
    • read
    • - edit
      • fileRegex: .(md|mdx)$

#### **4.6.6 Mode-Specific Instruction Files**

Beyond inline `customInstructions`, Roo-Cline loads additional instructions from **dedicated directories**:

**Directory Structure:**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── .roomodes # Mode definitions
├── .roo/
│ └── rules-{mode-slug}/ # Mode-specific rules
│ ├── 01-overview.md
│ ├── 02-patterns.md
│ └── 03-examples.md
└── src/


**Global Mode Rules:**

Enter fullscreen mode Exit fullscreen mode

~/.roo/
├── custom_modes.yaml # Global mode definitions
└── rules-{mode-slug}/ # Global mode rules
├── standards.md
└── templates.md


**Loading Behavior:**

1. Files in `.roo/rules-{slug}/` loaded **alphabetically**
2. Combined with `customInstructions` property in `.roomodes`
3. **Project rules** take precedence over global rules
4. System files automatically excluded (`.DS_Store`, `.swp`, etc.)

**Example: Test Engineer Mode Files**

**`.roomodes`:**

Enter fullscreen mode Exit fullscreen mode


yaml
customModes:

  • slug: test-engineer
    name: 🧪 Test Engineer
    roleDefinition: You are a testing specialist...

    Short inline instructions

    customInstructions: Follow TDD methodology. Write comprehensive tests.

    groups:

    • read
    • - edit
      • fileRegex: .test.(ts|tsx)$

**`.roo/rules-test-engineer/01-test-structure.md`:**

Enter fullscreen mode Exit fullscreen mode


markdown

Test Structure Guidelines

File Naming

  • Unit tests: [name].test.ts
  • Integration tests: [name].integration.test.ts
  • E2E tests: [name].e2e.test.ts

Test Organization

describe('ComponentOrFunction', () => {
  // Setup
  beforeEach(() => {
    // Reset state
  });

  // Happy path
  describe('when given valid input', () => {
    it('should return expected result', () => {
      // Test
    });
  });

  // Error cases
  describe('when given invalid input', () => {
    it('should throw validation error', () => {
      // Test
    });
  });

  // Edge cases
  describe('edge cases', () => {
    it('should handle empty input', () => {
      // Test
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

**`.roo/rules-test-engineer/02-mocking.md`:**

Enter fullscreen mode Exit fullscreen mode


markdown

Mocking Strategies

Mock External APIs (MSW)

import { rest } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  rest.get('/api/users', (req, res, ctx) => {
    return res(ctx.json([{ id: '1', name: 'Test' }]));
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Enter fullscreen mode Exit fullscreen mode

Mock Databases

const mockDb = {
  user: {
    findUnique: vi.fn(),
    create: vi.fn(),
  },
};
Enter fullscreen mode Exit fullscreen mode

Mock React Hooks

vi.mock('@/hooks/useAuth', () => ({
  useAuth: () => ({
    user: { id: '1', name: 'Test User' },
    isAuthenticated: true,
  }),
}));
Enter fullscreen mode Exit fullscreen mode

**Combined Effect:**

When Test Engineer mode is activated:
1. Loads `roleDefinition` from `.roomodes`
2. Loads `customInstructions` from `.roomodes`
3. Loads `01-test-structure.md` (appended)
4. Loads `02-mocking.md` (appended)

Total context = All four sources combined.

---

#### **4.6.7 Real-World Custom Mode Examples**

**Example 1: Architect Mode**

Enter fullscreen mode Exit fullscreen mode


yaml

  • slug: architect-mode name: 🏛️ TDD Architect

roleDefinition: >
You are an expert software architect specializing in maintainable,
modular, testable architectures for TDD workflows.

customInstructions: |-
## Process

### 1. Analyze Inputs
- Read context from planning documents
- Analyze requirements (BDD scenarios, user stories)
- Consider feature holistically (not just single function)

### 2. Propose Solutions
- Suggest 2-3 architectural designs
- Reduce code smells
- Ensure modularity (SOLID, DRY, KISS)
- Support testability

### 3. Trade-off Table
Present solutions comparing:
- Maintainability
- Simplicity
- Modularity
- Testability
- Scalability
- Performance

### 4. UML Diagram
Generate Mermaid diagram visualizing:
- Class relationships
- Data flow
- Component boundaries

### 5. ADR (Architecture Decision Record)
Document decision:
- **Context**: Problem being solved
- **Decision**: Chosen approach and why
- **Consequences**: Positive and negative outcomes

## Output Format
Save architecture document to `arch-[feature-name].md`
Use `write_to_file` tool
Enter fullscreen mode Exit fullscreen mode

groups:
- read
- - edit
- fileRegex: .md$
description: Markdown files only (ADRs, docs)

source: global


**Usage:**
Enter fullscreen mode Exit fullscreen mode

User: "Design architecture for user authentication system"

Architect Mode:

  1. Analyzes requirements
  2. Proposes 3 solutions:
    • JWT with refresh tokens
    • Session-based with Redis
    • OAuth2 with Supabase
  3. Creates comparison table
  4. Generates Mermaid diagram
  5. Writes ADR to arch-user-authentication.md

---

**Example 2: Database Migration Specialist**

Enter fullscreen mode Exit fullscreen mode


yaml

  • slug: db-migration name: 🗄️ Database Migration Specialist

roleDefinition: >
You are a database expert specializing in safe, reversible migrations.
You understand schema design, indexing, and zero-downtime deployments.

customInstructions: |-
## Migration Safety Checklist

Before creating migration:
- [ ] Backward compatible with current code?
- [ ] Includes rollback strategy?
- [ ] Indexes on foreign keys?
- [ ] NOT NULL columns have defaults?
- [ ] Large table? Consider batching

## Drizzle ORM Patterns

### Add Column (Safe)
Enter fullscreen mode Exit fullscreen mode
```typescript
// Migration
await db.schema
  .alterTable('users')
  .addColumn('email_verified', 'boolean', col => 
    col.defaultTo(false).notNull()
  );

// Rollback
await db.schema
  .alterTable('users')
  .dropColumn('email_verified');
```
Enter fullscreen mode Exit fullscreen mode
### Rename Column (Two-Phase)

**Phase 1** (Deploy code reading both):
Enter fullscreen mode Exit fullscreen mode
```typescript
// Add new column
await db.schema
  .alterTable('users')
  .addColumn('full_name', 'text');

// Copy data
await db.execute(sql`
  UPDATE users SET full_name = name
`);

// Update code to read from both
```
Enter fullscreen mode Exit fullscreen mode
**Phase 2** (After deploy):
Enter fullscreen mode Exit fullscreen mode
```typescript
// Drop old column
await db.schema
  .alterTable('users')
  .dropColumn('name');
```
Enter fullscreen mode Exit fullscreen mode
## Zero-Downtime Strategy
1. Make schema change backward compatible
2. Deploy schema change
3. Deploy code using new schema
4. Remove old schema (if needed)
Enter fullscreen mode Exit fullscreen mode

groups:
- read
- - edit
- fileRegex: (migrations/.|..schema.ts)$
description: Migration files and schema only
- command # Can run migrations

source: project


---

**Example 3: API Documentation Generator**

Enter fullscreen mode Exit fullscreen mode


yaml

  • slug: api-docs name: 📡 API Documentation Generator

roleDefinition: >
You are an API documentation specialist. You create comprehensive,
accurate API documentation from code, including OpenAPI specs.

customInstructions: |-
## Documentation Standards

For each endpoint, include:
- **Path**: Full endpoint path
- **Method**: GET, POST, PUT, DELETE
- **Description**: What it does
- **Authentication**: Required auth level
- **Request**: Parameters and body schema
- **Response**: Success and error formats
- **Examples**: curl and code samples

### OpenAPI Schema Format
Enter fullscreen mode Exit fullscreen mode
```yaml
paths:
  /api/users/{id}:
    get:
      summary: Get user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: User not found
```
Enter fullscreen mode Exit fullscreen mode
## Code Example Template
Enter fullscreen mode Exit fullscreen mode
```typescript
// Fetch user by ID
const response = await fetch('/api/users/123', {
  headers: {
    'Authorization': `Bearer ${token}`,
  },
});

if (!response.ok) {
  throw new Error('Failed to fetch user');
}

const user = await response.json();
console.log(user);
```
Enter fullscreen mode Exit fullscreen mode
## Generate From
- tRPC routers
- Express routes
- Next.js API routes
- FastAPI endpoints
Enter fullscreen mode Exit fullscreen mode

groups:
- read # Read API code
- - edit
- fileRegex: (docs/api/.*.md|openapi.yaml)$
description: API documentation only
- browser # Research API standards

source: global


---

#### **4.6.8 Creating and Managing Modes**

**Method 1: Ask Roo (Easiest)**

Enter fullscreen mode Exit fullscreen mode

Chat with Roo: "Create a new mode called 'Frontend Specialist'.
It should only be able to edit React component files (*.tsx, *.jsx).
Focus on component design and performance optimization."


Roo generates the YAML configuration and offers to save it to `.roomodes`.

---

**Method 2: Modes UI**

1. Open Roo Code panel
2. Click mode dropdown → Settings icon (⚙️)
3. Click `+` (New Mode)
4. Fill form:
   - **Name**: Display name
   - **Slug**: Unique ID (auto-generated from name)
   - **Description**: When to use this mode
   - **Save Location**: Project or Global
   - **Role Definition**: AI's identity
   - **Tool Permissions**: Select checkboxes, add regex restrictions
   - **Custom Instructions**: Additional guidelines
5. Click "Create Mode"

---

**Method 3: Manual Edit**

**Global modes:**
1. Modes page → "Edit Global Modes"
2. Opens `~/.roo/custom_modes.yaml` in editor
3. Add mode YAML manually
4. Save and reload

**Project modes:**
1. Create/edit `.roomodes` in project root
2. Add mode YAML
3. Reload VS Code window (Cmd/Ctrl + Shift + P → "Reload Window")

---

**Import/Export for Team Sharing**

**Export:**
1. Navigate to Modes view
2. Select mode
3. Click Export (download icon)
4. Choose save location
5. Shares YAML file with mode definition + bundled rule files

**Export Format:**
Enter fullscreen mode Exit fullscreen mode


yaml
customModes:

  • slug: my-custom-mode
    name: My Custom Mode
    roleDefinition: You are a helpful assistant.
    groups: ["read", "edit"]

    Rule files embedded

    rulesFiles:

    • relativePath: rules-my-custom-mode/rules.md content: | These are the rules for my custom mode.

**Import:**
1. Click Import (upload icon)
2. Select YAML file
3. Choose import level:
   - **Project**: Mode + rules → `.roomodes` + `.roo/rules-{slug}/`
   - **Global**: Mode + rules → `~/.roo/custom_modes.yaml` + `~/.roo/rules-{slug}/`
4. Edit slug in YAML before import if you want different ID

**Team Workflow:**
1. Developer creates mode (e.g., `security-auditor.yaml`)
2. Commits to shared repository or shares via Slack
3. Team members import mode
4. Everyone has consistent Security Auditor behavior

---

#### **4.6.9 Comparison Table and Use Case Recommendations**

| Feature | Cline | Roo-Cline |
|---------|-------|-----------|
| **Configuration** | Plain Markdown | YAML modes + Markdown |
| **Complexity** | Simple, beginner-friendly | Advanced, power users |
| **File Format** | `.clinerules` (file or dir) | `.roomodes` (YAML) |
| **Modes** | Single behavior | Multiple specialized modes |
| **Tool Permissions** | All tools available | Granular per-mode permissions |
| **File Restrictions** | None (global rules) | Regex-based per-mode |
| **Model Assignment** | Single model | Sticky models per mode |
| **Use Case** | General development | Complex workflows, specialized tasks |
| **Team Adoption** | Easy (just Markdown) | Requires YAML knowledge |
| **Cost Optimization** | Manual model switching | Automatic (cheap model for docs, powerful for code) |
| **Security** | Trust-based | Permission-based |

**When to Choose Cline:**

✅ **Use Cline if:**
- You want simple, straightforward configuration
- Your team prefers Markdown over YAML
- Human-in-the-loop is your primary workflow
- You don't need specialized modes
- Onboarding non-technical team members
- Quick setup is priority

**Example Cline User:** Freelance developer building standard web apps, occasional AI assistance for boilerplate and debugging.

---

**When to Choose Roo-Cline:**

✅ **Use Roo-Cline if:**
- You need granular control over AI behavior
- Working on large, complex codebases
- Different team members need different permissions
- Cost optimization through model switching is important
- You have specialized workflows (TDD, architecture, security audits)
- Want to restrict AI to specific file types
- Need mode-based context switching

**Example Roo-Cline User:** Enterprise team with:
- **Architects** using Architect mode (design docs only)
- **Developers** using Code mode (code editing)
- **QA Engineers** using Test mode (test files only)
- **Tech Writers** using Docs mode (Markdown only)
- **Security** using Audit mode (read-only analysis)

---

**Migration Path: Cline → Roo-Cline**

**Step 1: Install Roo-Cline** (both can coexist)

**Step 2: Convert Existing Rules**

Enter fullscreen mode Exit fullscreen mode


bash

Your existing Cline rules

.clinerules

or

.clinerules/
01-standards.md
02-testing.md


**Create `.roomodes`:**

Enter fullscreen mode Exit fullscreen mode


yaml
customModes:

  • slug: code
    name: 💻 Code (from Cline rules)

    Copy content from .clinerules into customInstructions

    customInstructions: |-
    [Paste your Cline rules here]

    groups:

    • read
    • edit
    • command

**Or Better: Create Specialized Modes**

Enter fullscreen mode Exit fullscreen mode


yaml
customModes:
# General coding

  • slug: code name: 💻 Code customInstructions: |- [Core coding standards from .clinerules] groups: [read, edit, command]

# Documentation writing

  • slug: docs name: 📝 Documentation customInstructions: |- [Documentation guidelines from .clinerules] groups:
    • read
    • - edit
      • fileRegex: .md$
    • browser

# Testing

  • slug: test name: 🧪 Testing customInstructions: |- [Testing standards from .clinerules] groups:
    • read
    • - edit
      • fileRegex: .test.(ts|tsx)$
    • command

**Step 3: Test Each Mode**

Try each mode with typical tasks:
- Code mode: Implement feature
- Docs mode: Update README
- Test mode: Write tests

**Step 4: Refine Permissions**

Based on usage, adjust `fileRegex` patterns and tool permissions.

---

This comprehensive Cline and Roo-Cline guide provides everything needed to:
1. **Start simple** with Cline's Markdown rules
2. **Scale up** to Roo-Cline's modes when complexity demands it
3. **Understand trade-offs** between simplicity and control
4. **Migrate** between tools as needs evolve

Both tools excel in their niches: **Cline for ease of use**, **Roo-Cline for power and flexibility**.

---

### **4.7 Zed Configuration**

Zed takes a fundamentally different architectural approach: **Markdown for AI instructions, JSON for editor settings**—no TOML for AI rules despite common misconceptions.

#### **4.7.1 The Dual-System Architecture**

**Critical Distinction:**

| System | Format | Purpose | Example Files |
|--------|--------|---------|---------------|
| **Editor Settings** | JSON | Configure IDE behavior, LSP, formatters, keybindings | `.zed/settings.json`, `~/.config/zed/settings.json` |
| **AI Instructions** | Markdown | Natural language guidance for AI agents | `.rules`, `.cursorrules`, `AGENTS.md` |

**Why This Matters:**

The confusion arose because:
1. ❌ **Zed does NOT use `.zed/rules.toml`** for AI configuration
2. ✅ **Zed DOES use TOML** for extension development (`extension.toml`) and language configs
3. ✅ **Zed reads `.rules` (Markdown)** for AI agent instructions

**What `.zed/settings.json` Contains:**

Enter fullscreen mode Exit fullscreen mode


json
{
// Editor appearance
"theme": "One Dark",
"buffer_font_size": 14,

// Language server configuration
"lsp": {
"typescript-language-server": {
"initialization_options": {
"preferences": {
"includeInlayParameterNameHints": "all"
}
}
}
},

// Formatter settings
"formatter": {
"language_server": {
"name": "prettier"
}
},

// AI Agent configuration (model selection)
"agent": {
"default_model": {
"provider": "anthropic",
"model": "claude-3-5-sonnet-20241022"
},
"inline_assistant_model": {
"provider": "openai",
"model": "gpt-4o"
}
},

// Language-specific overrides
"languages": {
"TypeScript": {
"tab_size": 2,
"format_on_save": "on"
}
}
}


**What `.rules` (Markdown) Contains:**

Enter fullscreen mode Exit fullscreen mode


markdown

Project Rules for AI Assistant

Tech Stack

  • TypeScript 5.4, Next.js 15, React 19
  • Tailwind CSS 4.0
  • tRPC for APIs

Coding Standards

  • Strict TypeScript mode
  • Functional components only
  • Server Components by default

Testing

  • Vitest for unit tests
  • Playwright for E2E
  • 80% coverage minimum

#### **4.7.2 Rule File Priority Order**

Zed scans the **project root** for AI rule files in this priority:

| Priority | Filename | Source Tool |
|----------|----------|-------------|
| 1 | `.rules` | ⭐ Zed-specific (recommended) |
| 2 | `.cursorrules` | Cursor IDE compatibility |
| 3 | `.windsurfrules` | Windsurf compatibility |
| 4 | `.clinerules` | Cline compatibility |
| 5 | `.github/copilot-instructions.md` | GitHub Copilot compatibility |
| 6 | `AGENT.md` or `AGENTS.md` | Alternative open standard |
| 7 | `CLAUDE.md` | Claude Code compatibility |
| 8 | `GEMINI.md` | Gemini CLI compatibility |

**Important:** **Only the first matching file is used.** If you have both `.rules` and `.cursorrules`, Zed uses `.rules` and ignores `.cursorrules`.

**Cross-Tool Compatibility Strategy:**

**Option 1: Use `.rules` + Symlinks**

Enter fullscreen mode Exit fullscreen mode


bash

Create Zed-native file

touch .rules

Symlink for other tools

ln -s .rules .cursorrules
ln -s .rules .windsurfrules
ln -s .rules AGENTS.md


**Option 2: Use Universal `AGENTS.md`**

Enter fullscreen mode Exit fullscreen mode


bash

Create universal standard file

touch AGENTS.md

Zed will find and use it (priority 6)

Other tools also recognize it


**Option 3: Tool-Specific (Separate Files)**

Enter fullscreen mode Exit fullscreen mode


bash

Each tool gets its own file

touch .rules # For Zed
touch .cursorrules # For Cursor
touch .windsurfrules # For Windsurf

Requires maintaining multiple files (not recommended)


#### **4.7.3 Plain Markdown Format (No Schema)**

**Key Principle:** Zed passes the **entire file content as-is** to the LLM. No parsing, no validation, no schema.

**Advantages:**

✅ **Maximum flexibility:** Write in any style that works  
✅ **No learning curve:** Just Markdown  
✅ **Natural for LLMs:** Models are trained on Markdown docs  
✅ **Easy to maintain:** Human-readable, clean git diffs  
✅ **Cross-tool compatible:** Works with any AI assistant  

**Disadvantages:**

❌ **No validation:** Typos and errors not caught  
❌ **No structure enforcement:** Can become disorganized  
❌ **No conditional loading:** Entire file always loaded  

**Complete Zed `.rules` Example:**

Enter fullscreen mode Exit fullscreen mode


markdown

Zed AI Rules for [Project Name]

Project Context

Type: Full-stack web application

Stack: Next.js 15 + TypeScript + PostgreSQL

Architecture: Monorepo with Turborepo

Deployment: Vercel

Technology Stack

Frontend

  • Framework: Next.js 15.1 (App Router, NOT Pages Router)
  • Language: TypeScript 5.4 (strict mode)
  • Styling: Tailwind CSS 4.0
  • Components: shadcn/ui + Radix UI primitives
  • State Management:
    • Server State: TanStack Query v5
    • Client State: Zustand 4.5
    • Forms: React Hook Form + Zod

Backend

  • API: tRPC 11 (type-safe)
  • Database: PostgreSQL 16
  • ORM: Drizzle ORM 0.35
  • Auth: NextAuth.js v5

DevOps

  • Monorepo: Turborepo 2.0
  • Package Manager: pnpm 9.0 (NOT npm/yarn)
  • Testing: Vitest 2.0, Playwright 1.45
  • CI/CD: GitHub Actions

Directory Structure

apps/
├── web/                  # Next.js frontend
│   ├── app/             # App Router pages
│   ├── components/      # React components
│   └── lib/             # Client utilities
packages/
├── ui/                  # Shared component library
├── database/            # Drizzle schema
├── types/               # Shared TypeScript types
└── config/              # Shared configs
Enter fullscreen mode Exit fullscreen mode

Key Directories:

  • apps/web/app/: Next.js routes (App Router)
  • apps/web/components/ui/: shadcn/ui primitives
  • packages/database/: Drizzle schema definitions

Coding Standards

TypeScript Rules

Type Annotations

All functions MUST have explicit return types:

// ✅ CORRECT
export function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ WRONG - No return type
export function calculateTotal(items: Item[]) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Avoid any

// ✅ Use `unknown` + type guards
function processData(data: unknown) {
  if (typeof data === 'object' && data !== null && 'id' in data) {
    return data.id; // Type-safe
  }
  throw new Error('Invalid data shape');
}

// ❌ Never use `any`
function processData(data: any) {
  return data.id; // No type safety!
}
Enter fullscreen mode Exit fullscreen mode

Error Handling Pattern

// ✅ REQUIRED: Result type pattern
type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

async function fetchUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.query.users.findFirst({
      where: eq(users.id, id)
    });

    if (!user) {
      return { success: false, error: 'User not found' };
    }

    return { success: true, data: user };
  } catch (error) {
    logger.error('fetchUser failed', { id, error });
    return { success: false, error: 'Database error' };
  }
}

// ❌ FORBIDDEN: Silent error swallowing
async function fetchUser(id: string) {
  try {
    return await db.query.users.findFirst({ where: eq(users.id, id) });
  } catch {
    return null; // Silent failure!
  }
}
Enter fullscreen mode Exit fullscreen mode

React Patterns

Server vs Client Components

// ✅ Server Component (default - no directive)
async function UserProfilePage({ params }: { params: { id: string } }) {
  // Can fetch data directly in Server Components
  const user = await db.query.users.findFirst({
    where: eq(users.id, params.id)
  });

  return <UserProfile user={user} />;
}

// ✅ Client Component (only when needed)
'use client';

import { useState } from 'react';

export function InteractiveCounter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

// Add 'use client' ONLY when:
// - Using hooks (useState, useEffect, etc.)
// - Event handlers (onClick, onChange, etc.)
// - Browser APIs (window, localStorage, etc.)
Enter fullscreen mode Exit fullscreen mode

Component Size Limits

  • Maximum 200 lines per component
  • If exceeded: Extract sub-components
  • Use composition over props drilling
// ✅ Composition pattern
<Card>
  <CardHeader>
    <CardTitle>User Profile</CardTitle>
  </CardHeader>
  <CardContent>
    <UserDetails user={user} />
  </CardContent>
  <CardFooter>
    <EditButton />
  </CardFooter>
</Card>

// ❌ Props drilling
<Card 
  title="User Profile"
  content={<UserDetails user={user} />}
  footer={<EditButton />}
  headerClassName="..."
  contentClassName="..."
/>
Enter fullscreen mode Exit fullscreen mode

Import Organization

// 1. React and external libraries
import { useState, useEffect } from 'react';
import { z } from 'zod';

// 2. Internal packages (@repo/*)
import { Button } from '@repo/ui';
import { User } from '@repo/types';

// 3. Application modules (@/*)
import { trpc } from '@/lib/trpc/client';
import { cn } from '@/lib/utils';

// 4. Relative imports
import { UserCard } from './UserCard';
import type { UserCardProps } from './types';

// 5. Styles
import './styles.css';
Enter fullscreen mode Exit fullscreen mode

Testing Requirements

Coverage Targets

  • Unit Tests: 80% minimum (business logic)
  • Integration Tests: 70% minimum (API endpoints)
  • E2E Tests: Critical user flows only

Test Commands

pnpm test                 # Run Vitest unit tests
pnpm test:watch           # Watch mode
pnpm test:coverage        # Generate coverage report
pnpm test:e2e             # Run Playwright E2E tests
Enter fullscreen mode Exit fullscreen mode

Unit Test Structure (Vitest)

import { describe, it, expect, beforeEach } from 'vitest';

describe('UserService', () => {
  let service: UserService;

  beforeEach(() => {
    // ARRANGE: Setup
    service = new UserService(mockDb);
  });

  it('creates user with valid data', async () => {
    // ARRANGE: Prepare data
    const userData = { email: 'test@example.com', name: 'Test' };

    // ACT: Execute
    const result = await service.createUser(userData);

    // ASSERT: Verify
    expect(result.success).toBe(true);
    expect(result.data).toMatchObject(userData);
  });

  it('rejects invalid email', async () => {
    const invalidData = { email: 'not-an-email', name: 'Test' };
    const result = await service.createUser(invalidData);

    expect(result.success).toBe(false);
    expect(result.error).toContain('Invalid email');
  });
});
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls

Issue 1: Hot Reload with tRPC

Symptom: Changes to tRPC routers don't reflect

Solution: Restart dev server when adding/removing procedures

Issue 2: Mixing Server/Client Components

Symptom: "useState can only be used in Client Components"

Solution: Add 'use client' directive at top of file

Issue 3: Environment Variables

Symptom: process.env.NEXT_PUBLIC_VAR is undefined

Solution: All client-accessible vars MUST have NEXT_PUBLIC_ prefix

# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com  # ✅ Client-side
DATABASE_URL=postgresql://...                # ❌ Server-only
Enter fullscreen mode Exit fullscreen mode

Important Notes

  • Package Manager: Use pnpm commands (NOT npm)
  • JWT Storage: HttpOnly cookies ONLY (NEVER localStorage)
  • Rate Limiting: 100 req/min (public), 1000 req/min (authenticated)
  • API Prefix: All routes use /api/v1/*
  • Git Workflow: Feature branches, Conventional Commits, 1 approval required

Working with Zed AI

When using Zed's Agent Panel:

  • Be specific about file locations and changes
  • Reference patterns from existing code
  • Ask for diffs instead of full file replacements
  • Verify changes before accepting

These rules are optimized for Zed AI Agent. Last updated: 2025-11-29


**Why This Works:**

1. **No parsing overhead:** Zed passes entire file to LLM (efficient)
2. **Natural language:** LLMs excel at understanding Markdown docs
3. **Flexible structure:** Organize however makes sense for your project
4. **Cross-tool compatible:** Same file works with Cursor, Windsurf, Claude Code, etc.

#### **4.7.4 Integration with Agent Panel**

**How Zed Loads Rules:**

1. **User opens Agent Panel** (`cmd-shift-?` or sparkles icon)
2. **Zed scans project root** for rule files (priority order above)
3. **First matching file loaded** into system prompt
4. **User starts chat** or makes edit request
5. **AI receives**:
   - Model configuration from `.zed/settings.json` (`agent` section)
   - Instructions from `.rules` (or other rule file)
   - Current file context
   - User's request
6. **AI generates response** following loaded rules
7. **User reviews and applies** changes

**Agent Panel Workflow Example:**

Enter fullscreen mode Exit fullscreen mode

User: "Add error handling to the fetchUser function"

Zed Agent:

  1. Loads .rules (sees error handling pattern requirement)
  2. Loads src/api/users.ts (current file)
  3. Applies Result pattern from rules
  4. Generates:

async function fetchUser(id: string): Promise> {
try {
const user = await db.query.users.findFirst({
where: eq(users.id, id)
});

if (!user) {
  return { success: false, error: 'User not found' };
}

return { success: true, data: user };
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
logger.error('fetchUser failed', { id, error });
return { success: false, error: 'Database error' };
}
}

  1. User reviews diff
  2. User accepts or requests modifications

**Model Configuration in Settings:**

Enter fullscreen mode Exit fullscreen mode


json
// .zed/settings.json

{
"agent": {
// Main chat model
"default_model": {
"provider": "anthropic",
"model": "claude-3-5-sonnet-20241022"
},

// Inline assistant (faster, cheaper)
"inline_assistant_model": {
  "provider": "openai",
  "model": "gpt-4o-mini"
}
Enter fullscreen mode Exit fullscreen mode

}
}


**Global vs Project Settings:**

| Setting | File | Scope |
|---------|------|-------|
| **Global** | `~/.config/zed/settings.json` | All projects |
| **Project** | `.zed/settings.json` | Current project only |

**Precedence:** Project settings override global settings.

#### **4.7.5 Best Practices for Zed Rules**

**1. Keep Under 500 Lines**

Zed loads entire file into context. Aim for:
- **Small projects**: 100-200 lines
- **Medium projects**: 200-350 lines
- **Large projects**: 350-500 lines
- **If exceeded**: Split into multiple files and choose tool that supports that (Cursor, Roo-Cline)

**2. Prioritize High-Impact Rules**

Enter fullscreen mode Exit fullscreen mode


markdown

✅ GOOD: Specific, actionable rules

  • TypeScript strict mode required
  • Server Components by default (add 'use client' only when needed)
  • Result type for error handling
  • 80% test coverage minimum

❌ BAD: Vague, generic advice

  • Write clean code
  • Follow best practices
  • Be consistent
  • Make it performant

**3. Use Clear Hierarchy**

Enter fullscreen mode Exit fullscreen mode


markdown

Top-Level: Major Categories

Second-Level: Specific Topics

Third-Level: Implementation Details

  • Bullet points for specific rules
  • Code examples with ✅/❌ indicators

**4. Include Both Good and Bad Examples**

Enter fullscreen mode Exit fullscreen mode


markdown

Error Handling

✅ CORRECT

try {
  await operation();
} catch (error) {
  logger.error('Context', { error });
  throw new AppError('User message', 500);
}
Enter fullscreen mode Exit fullscreen mode

❌ WRONG

try {
  await operation();
} catch {
  // Silent failure
}
Enter fullscreen mode Exit fullscreen mode

**5. Version Control the File**

Enter fullscreen mode Exit fullscreen mode


bash

Commit .rules with your code

git add .rules
git commit -m "docs: update AI rules for new authentication flow"

Track changes over time

git log --oneline .rules


**6. Update Incrementally**

Don't try to write perfect rules upfront:
1. Start with 10-15 core rules
2. Use Zed AI for a week
3. Note friction points (where AI gets it wrong)
4. Add specific rules addressing those issues
5. Repeat

**7. Use Markdown Features**

Enter fullscreen mode Exit fullscreen mode


markdown

State Management

Use Case Solution Example
Server data TanStack Query useQuery('users', fetchUsers)
Client state useState const [open, setOpen] = useState(false)
Global client Zustand const user = useUserStore(s => s.user)

API Patterns

Important: All endpoints return standardized JSON format

{
  "success": boolean,
  "data": T | null,
  "error": string | null
}
Enter fullscreen mode Exit fullscreen mode

---

#### **4.7.6 Zed + Multi-Tool Strategy**

**Scenario: Team Uses Zed + Cursor + Windsurf**

**Option 1: Universal File with Symlinks**

Enter fullscreen mode Exit fullscreen mode


bash

Create Zed-native file

vim .rules

[Add all project rules]

Symlink for other tools

ln -s .rules .cursorrules
ln -s .rules .windsurfrules
ln -s .rules AGENTS.md

Now all tools read same rules


**Option 2: Shared `AGENTS.md` Standard**

Enter fullscreen mode Exit fullscreen mode


bash

Create universal standard file (recognized by all tools)

vim AGENTS.md

[Add all project rules]

Zed finds it (priority 6)

Cursor finds it (fallback)

Windsurf finds it (fallback)

Claude Code finds it

Aider can load it via .aider.conf.yml


**Option 3: Tool-Specific with Shared Core**

Enter fullscreen mode Exit fullscreen mode


bash

Shared core rules

vim PROJECT_RULES.md

Tool-specific wrappers

.rules (Zed)

cat > .rules << 'EOF'

Zed AI Rules

See PROJECT_RULES.md for complete guidelines.

Zed-Specific Notes

  • Use Agent Panel for complex refactoring
  • Inline assistant for quick fixes EOF

.cursorrules (Cursor)

cat > .cursorrules << 'EOF'

Cursor Rules

See PROJECT_RULES.md for complete guidelines.

Cursor-Specific Notes

  • Use Composer for multi-file changes
  • Use CMD-K for inline edits EOF

---

### Summary: Zed's Philosophy

Zed's approach reflects a **separation of concerns**:

- **Settings (JSON)**: Machine-readable config (editor behavior, model selection, LSP)
- **Rules (Markdown)**: Human-readable instructions (coding standards, patterns)

This architecture:
✅ Keeps AI instructions simple and portable  
✅ Avoids vendor lock-in (rules work with any tool)  
✅ Leverages Markdown's strengths for natural language  
✅ Makes cross-tool collaboration seamless  

**For Zed users:** Focus on writing clear, concise Markdown rules in `.rules`, configure your models in `.zed/settings.json`, and enjoy Zed's fast, native AI integration.

---

This completes the comprehensive Zed configuration guide, clarifying the architectural split and providing production-ready examples and strategies.

---

## **V. Multi-Tool Strategy & Portability**

Managing AI coding rules across multiple tools is no longer optional—it's the reality of modern development teams. This section provides battle-tested strategies for maintaining consistency while supporting tool diversity.

### **5.1 The AGENTS.md Standard**

**AGENTS.md** has emerged as the closest thing to a universal standard, with adoption across 20,000+ open-source projects as of mid-2025.

#### **5.1.1 What Is AGENTS.md?**

**Origin**: Proposed by the open-source community in early 2024 as a tool-agnostic format for AI coding instructions.

**Specification**: https://agents.md

**Core Principles:**
1. **Plain Markdown** (no proprietary formats)
2. **Human-readable** (developers can edit without tools)
3. **Git-friendly** (clean diffs, easy reviews)
4. **Tool-agnostic** (works with any AI assistant)

**Tool Support:**

| Tool | Support Level | Notes |
|------|---------------|-------|
| **Cursor** | ✅ Native (fallback) | Reads `AGENTS.md` if no `.cursor/rules/` found |
| **Windsurf** | ✅ Native (fallback) | Reads if no `.windsurfrules` present |
| **Claude Code** | ✅ Native | Loads `AGENTS.md` (priority after `CLAUDE.md`) |
| **Aider** | ✅ Via config | Load via `read: [AGENTS.md]` in `.aider.conf.yml` |
| **Continue.dev** | ✅ Via rules | Reference in `.continue/rules/` |
| **Cline** | ✅ Native (fallback) | Reads if no `.clinerules` found |
| **Zed** | ✅ Native | Priority 6 in file scan order |
| **GitHub Copilot** | ⚠️ Manual | Must reference or symlink to `.github/copilot-instructions.md` |
| **JetBrains** | ⚠️ Manual | Can symlink to `.aiassistant/rules/` |

#### **5.1.2 Complete AGENTS.md Template**

Enter fullscreen mode Exit fullscreen mode


markdown

AGENTS.md

Version: 1.0.0

Last Updated: 2025-11-29

Compatible With: Cursor, Windsurf, Claude Code, Cline, Zed, Aider, Continue.dev


PROJECT OVERVIEW

Name: [Your Project Name]

Description: [One-sentence description of what this project does]

Primary Goal: [Main objective or problem being solved]

Example:

Full-stack e-commerce platform built with Next.js and PostgreSQL.

Primary Goal: Support 10,000 concurrent users with <100ms API response times.


TECHNOLOGY STACK

Frontend

  • Framework: Next.js 15.1 (App Router)
  • Language: TypeScript 5.4 (strict mode)
  • Styling: Tailwind CSS 4.0
  • State Management: TanStack Query + Zustand
  • Testing: Vitest, Testing Library, Playwright

Backend

  • Runtime: Node.js 20.11 LTS
  • Framework: Express.js + tRPC 11
  • Database: PostgreSQL 16
  • ORM: Drizzle ORM 0.35
  • Authentication: NextAuth.js v5

DevOps

  • Monorepo: Turborepo 2.0
  • Package Manager: pnpm 9.0 (NOT npm/yarn)
  • CI/CD: GitHub Actions
  • Hosting: Vercel (production), Railway (staging)

PROJECT STRUCTURE

root/
├── apps/
│   ├── web/                  # Next.js frontend
│   │   ├── app/             # App Router pages
│   │   ├── components/      # React components
│   │   └── lib/             # Client utilities
│   └── api/                 # Standalone API (future)
├── packages/
│   ├── ui/                  # Shared component library
│   ├── database/            # Drizzle schema & migrations
│   ├── types/               # Shared TypeScript types
│   └── config/              # ESLint, TypeScript configs
├── docs/                    # Documentation
├── scripts/                 # Build scripts
└── AGENTS.md                # This file
Enter fullscreen mode Exit fullscreen mode

Key Directories:

  • apps/web/app/: Next.js routes (App Router, NOT Pages Router)
  • apps/web/components/ui/: shadcn/ui primitives
  • packages/database/: Drizzle ORM schema definitions

CODING STANDARDS

Universal Principles

  • Type Safety: TypeScript strict mode, explicit return types
  • Error Handling: Never swallow errors silently
  • Testing: 80% coverage minimum for business logic
  • Documentation: JSDoc for public APIs

TypeScript Rules

Type Annotations

// ✅ ALWAYS: Explicit return types
export function calculateTotal(items: Item[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ❌ NEVER: Implicit return types
export function calculateTotal(items: Item[]) {
  return items.reduce((sum, item) => sum + item.price, 0);
}
Enter fullscreen mode Exit fullscreen mode

Error Handling Pattern

// ✅ REQUIRED: Result type
type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

async function fetchUser(id: string): Promise<Result<User>> {
  try {
    const user = await db.query.users.findFirst({
      where: eq(users.id, id)
    });

    if (!user) {
      return { success: false, error: 'User not found' };
    }

    return { success: true, data: user };
  } catch (error) {
    logger.error('fetchUser failed', { id, error });
    return { success: false, error: 'Database error occurred' };
  }
}
Enter fullscreen mode Exit fullscreen mode

React Patterns

Server vs Client Components

// ✅ Server Component (default, no directive)
async function UserProfilePage({ params }: { params: { id: string } }) {
  const user = await db.query.users.findFirst({
    where: eq(users.id, params.id)
  });

  return <UserProfile user={user} />;
}

// ✅ Client Component (only when needed)
'use client';

import { useState } from 'react';

export function InteractiveCounter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Enter fullscreen mode Exit fullscreen mode

Add 'use client' ONLY when:

  • Using hooks (useState, useEffect, useContext)
  • Event handlers (onClick, onChange)
  • Browser APIs (window, localStorage)
  • Third-party libraries using client features

Import Organization

// 1. External dependencies
import { useState, useEffect } from 'react';
import { z } from 'zod';

// 2. Internal packages
import { Button } from '@repo/ui';
import { User } from '@repo/types';

// 3. Application modules
import { trpc } from '@/lib/trpc/client';
import { cn } from '@/lib/utils';

// 4. Relative imports
import { UserCard } from './UserCard';

// 5. Styles
import './styles.css';
Enter fullscreen mode Exit fullscreen mode

TESTING APPROACH

Coverage Requirements

  • Unit Tests: 80% minimum (business logic)
  • Integration Tests: 70% minimum (API endpoints)
  • E2E Tests: Critical user flows only

Test Structure (AAA Pattern)

describe('FeatureName', () => {
  it('should handle happy path', () => {
    // ARRANGE: Set up test data
    const input = createTestData();

    // ACT: Execute function
    const result = performOperation(input);

    // ASSERT: Verify outcome
    expect(result).toEqual(expected);
  });

  it('should handle error case', () => {
    // Test error scenarios
  });

  it('should handle edge case', () => {
    // Test boundary conditions
  });
});
Enter fullscreen mode Exit fullscreen mode

Commands

pnpm test                   # Run unit tests
pnpm test:watch             # Watch mode
pnpm test:coverage          # Generate coverage report
pnpm test:e2e               # Run E2E tests
Enter fullscreen mode Exit fullscreen mode

COMMON COMMANDS

Development

pnpm dev                    # Start dev server (localhost:3000)
pnpm build                  # Production build
pnpm lint                   # Run ESLint
pnpm type-check             # TypeScript validation
pnpm format                 # Run Prettier
Enter fullscreen mode Exit fullscreen mode

Database

pnpm db:push                # Push schema to database
pnpm db:studio              # Open Drizzle Studio
pnpm db:generate            # Generate migrations
pnpm db:migrate             # Apply migrations
Enter fullscreen mode Exit fullscreen mode

Deployment

pnpm deploy:staging         # Deploy to staging
pnpm deploy:production      # Deploy to production
Enter fullscreen mode Exit fullscreen mode

KNOWN ISSUES & WORKAROUNDS

Issue 1: Hot Reload with tRPC

Symptom: Changes to tRPC routers don't reflect in frontend

Solution: Restart dev server when adding/removing procedures

Issue 2: Server Component Hydration Errors

Symptom: "Text content did not match" console errors

Solution: Ensure all async operations in Server Components are awaited

Issue 3: Environment Variables

Symptom: process.env.NEXT_PUBLIC_VAR is undefined on client

Solution: All client-accessible vars MUST have NEXT_PUBLIC_ prefix

# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com  # ✅ Client-accessible
DATABASE_URL=postgresql://...                # ❌ Server-only
Enter fullscreen mode Exit fullscreen mode

IMPORTANT NOTES

API

  • Rate Limiting: 100 req/min (public), 1000 req/min (authenticated)
  • Versioning: All routes prefixed with /api/v1/
  • Format: All endpoints return { success: boolean, data: T | null, error: string | null }

Authentication

  • JWT Expiration: Access tokens expire after 15 minutes
  • Refresh Tokens: Valid for 7 days, rotated on use
  • Storage: HttpOnly cookies ONLY (NEVER localStorage)

Security

  • Secrets: NEVER commit to git, use environment variables
  • Input Validation: ALWAYS validate with Zod schemas
  • SQL Injection: Use parameterized queries (Drizzle ORM handles this)

Git Workflow

  • Branches: feat/, fix/, docs/ prefixes
  • Commits: Conventional Commits format (feat:, fix:, docs:)
  • PRs: Require 1 approval + passing CI

DEPLOYMENT CHECKLIST

Before deploying:

  • [ ] Run full test suite: pnpm test
  • [ ] TypeScript check passes: pnpm type-check
  • [ ] Linter passes: pnpm lint --max-warnings 0
  • [ ] Production build succeeds: pnpm build
  • [ ] Environment variables configured in platform
  • [ ] Database migrations applied
  • [ ] Secrets rotated (if compromised)

WORKING WITH AI ASSISTANTS

General Guidelines

  • Be specific: Reference exact file paths and line numbers
  • Show examples: Provide existing code patterns to follow
  • Request diffs: Ask for changes in diff format for review
  • Verify output: Always review before accepting changes

Tool-Specific Notes

Cursor:

  • Use Composer (CMD-I) for multi-file changes
  • Use CMD-K for inline edits
  • Rules auto-load from .cursor/rules/ (or falls back to this file)

Windsurf:

  • Use Cascade for deep reasoning tasks
  • Rules load from .windsurf/rules/ (or falls back to this file)
  • Wave 8+ supports multiple rule files with activation modes

Claude Code:

  • Use /init to generate project-specific rules
  • Use # key during coding to capture rules dynamically
  • Prefers CLAUDE.md but reads AGENTS.md as fallback

Aider:

  • Configure in .aider.conf.yml with read: [AGENTS.md]
  • Use --architect mode for complex refactoring
  • Conventions file is cached for efficiency

Cline/Roo-Cline:

  • Cline reads this file if no .clinerules present
  • Roo-Cline: Reference in mode-specific rules
  • Use rules bank pattern for multi-context projects

Zed:

  • Create .rules symlinked to AGENTS.md
  • Or Zed reads AGENTS.md directly (priority 6)
  • Configure models in .zed/settings.json

ADDITIONAL RESOURCES

  • Architecture Diagrams: docs/architecture.md
  • API Documentation: docs/api-reference.md
  • Database Schema: packages/database/schema.ts
  • Deployment Guide: docs/deployment.md

MAINTENANCE

How to Update This File

  1. When: Tech stack changes, new patterns emerge, issues discovered
  2. Process: Create PR, require 1 approval, update version and date
  3. Keep Concise: Target <50KB, link to external docs for details

Version History

  • 1.0.0 (2025-11-29): Initial AGENTS.md creation
  • Future versions documented here

This AGENTS.md file follows the universal standard for AI coding instructions.

Compatible with 10+ AI coding tools. For specification, see: https://agents.md


---

### **5.2 Single Source of Truth (SSOT) Architecture**

The SSOT pattern solves the multi-tool problem: **maintain one canonical file, distribute to tool-specific locations**.

#### **5.2.1 The Core Pattern**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── AGENTS.md # ⭐ Master file (SSOT)
├── .rules -> AGENTS.md # Symlink for Zed
├── .cursorrules -> AGENTS.md # Symlink for Cursor
├── .windsurfrules -> AGENTS.md # Symlink for Windsurf
├── .clinerules -> AGENTS.md # Symlink for Cline
├── CLAUDE.md -> AGENTS.md # Symlink for Claude Code
├── .github/
│ └── copilot-instructions.md -> ../../AGENTS.md # Copilot
└── .aiassistant/
└── rules/
└── main.md -> ../../../AGENTS.md # JetBrains


**Create Symlinks:**

**Unix/Linux/macOS:**
Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

sync-ai-rules.sh

Create symlinks to AGENTS.md

ln -sf AGENTS.md .rules
ln -sf AGENTS.md .cursorrules
ln -sf AGENTS.md .windsurfrules
ln -sf AGENTS.md .clinerules
ln -sf AGENTS.md CLAUDE.md

GitHub Copilot

mkdir -p .github
ln -sf ../AGENTS.md .github/copilot-instructions.md

JetBrains

mkdir -p .aiassistant/rules
ln -sf ../../AGENTS.md .aiassistant/rules/main.md

echo "✅ AI rules synced across all tools"


**Windows (PowerShell):**
Enter fullscreen mode Exit fullscreen mode


powershell

sync-ai-rules.ps1

New-Item -ItemType SymbolicLink -Path ".rules" -Target "AGENTS.md"
New-Item -ItemType SymbolicLink -Path ".cursorrules" -Target "AGENTS.md"
New-Item -ItemType SymbolicLink -Path ".windsurfrules" -Target "AGENTS.md"
New-Item -ItemType SymbolicLink -Path ".clinerules" -Target "AGENTS.md"
New-Item -ItemType SymbolicLink -Path "CLAUDE.md" -Target "AGENTS.md"

New-Item -ItemType Directory -Path ".github" -Force
New-Item -ItemType SymbolicLink -Path ".github\copilot-instructions.md" -Target "..\AGENTS.md"

Write-Host "✅ AI rules synced across all tools"


#### **5.2.2 Alternative: Copy Script (No Symlinks)**

For environments that don't support symlinks (or for files that need slight tool-specific variations):

Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

sync-ai-rules-copy.sh

echo "📋 Copying AGENTS.md to tool-specific locations..."

Direct copies

cp AGENTS.md .rules
cp AGENTS.md .cursorrules
cp AGENTS.md .windsurfrules
cp AGENTS.md .clinerules
cp AGENTS.md CLAUDE.md

GitHub Copilot

mkdir -p .github
cp AGENTS.md .github/copilot-instructions.md

JetBrains

mkdir -p .aiassistant/rules
cp AGENTS.md .aiassistant/rules/main.md

Aider (reference in config)

cat > .aider.conf.yml << 'EOF'
model: claude-3-5-sonnet-20241022
read:

  • AGENTS.md EOF

echo "✅ AI rules copied to all tool locations"
echo "⚠️ Remember to run this script after updating AGENTS.md"


**Add to Pre-Commit Hook:**

Enter fullscreen mode Exit fullscreen mode


bash

.git/hooks/pre-commit

!/bin/bash

Check if AGENTS.md was modified

if git diff --cached --name-only | grep -q "AGENTS.md"; then
echo "📋 AGENTS.md modified, syncing to other tools..."
./sync-ai-rules-copy.sh

# Stage the updated files
git add .rules .cursorrules .windsurfrules .clinerules CLAUDE.md
git add .github/copilot-instructions.md
git add .aiassistant/rules/main.md

echo "✅ Tool-specific rule files updated"
fi


#### **5.2.3 Hybrid Approach: Shared Core + Tool-Specific Layers**

For projects where tools need slightly different instructions:

**Directory Structure:**

Enter fullscreen mode Exit fullscreen mode

my-project/
├── AI_RULES.md # Core shared rules
├── .cursor/
│ └── rules/
│ ├── index.mdc # Imports AI_RULES.md + Cursor specifics
│ └── cursor-composer.mdc # Cursor-only: Composer mode tips
├── .windsurf/
│ └── rules/
│ ├── 01-shared.md -> ../../AI_RULES.md # Symlink
│ └── 02-cascade-specific.md # Windsurf-only: Cascade tips
├── .roo/
│ └── rules-code/
│ ├── shared.md -> ../../../AI_RULES.md
│ └── roo-modes.md # Roo-only: Mode switching guide
├── CLAUDE.md # Claude-specific wrapper
└── AGENTS.md -> AI_RULES.md # Public standard (symlink)


**Cursor `index.mdc` (Wrapper):**

Enter fullscreen mode Exit fullscreen mode

markdown

description: "Project-wide standards (shared across all tools)"

alwaysApply: true

Project Standards

See AI_RULES.md for complete shared rules across all AI tools.

Cursor-Specific Notes

Composer Mode (CMD-I)

Use Composer for:

  • Multi-file refactoring
  • Creating new features spanning multiple files
  • Architectural changes

Inline Edit (CMD-K)

Use CMD-K for:

  • Single-file changes
  • Quick fixes
  • Renaming across single file

CMD-L Chat

Use Chat for:

  • Asking questions
  • Exploring alternatives
  • Explaining code

**Windsurf `02-cascade-specific.md`:**

Enter fullscreen mode Exit fullscreen mode


markdown

Windsurf Cascade-Specific Guidelines

When to Use Cascade

  • Complex multi-step reasoning
  • Debugging hard-to-reproduce issues
  • Architectural planning
  • Code review and optimization

Cascade Best Practices

  • Give Cascade time to reason (don't interrupt)
  • Provide full context upfront
  • Let it propose solutions before implementing
  • Review its reasoning process

Flows (Wave 8+)

Use custom flows for:

  • TDD cycles (Red → Green → Refactor)
  • Deployment checklists
  • Code review procedures

**Claude Code `CLAUDE.md` (Wrapper):**

Enter fullscreen mode Exit fullscreen mode


markdown

Claude Code Instructions

Shared Rules

See AI_RULES.md for complete project standards.

Claude Code Workflow

/init Command

Use /init to generate project-specific rules.
Already done—this file is the result.

# Key During Coding

Press # key during sessions to capture recurring patterns.
Claude auto-updates CLAUDE.md.

@imports

Reference additional context:

  • @docs/architecture.md
  • @packages/database/schema.ts

**Benefits of Hybrid Approach:**

✅ **Shared baseline**: Core standards consistent across tools  
✅ **Tool-specific optimization**: Leverage unique features  
✅ **Maintainability**: Update core rules once, tool tips independently  
✅ **Flexibility**: Adapt to team's multi-tool reality  

---

### **5.3 Migration Workflows**

#### **5.3.1 Cursor → Aider Migration**

**Scenario**: Developer uses Cursor, wants to add Aider for CLI workflow.

**Step 1: Export Cursor Rules**

Enter fullscreen mode Exit fullscreen mode


bash

If using .cursorrules (legacy)

cp .cursorrules AGENTS.md

If using .cursor/rules/ (modern)

Combine multiple .mdc files into one

cat .cursor/rules/*.mdc > AGENTS.md

Clean up YAML frontmatter (Aider doesn't need it)

Manually edit AGENTS.md to remove --- blocks


**Step 2: Create Aider Config**

Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

model: claude-3-5-sonnet-20241022
weak-model: gpt-4o-mini

Load the shared rules

read:

  • AGENTS.md

Aider-specific settings

auto-lint: true
lint-cmd:

  • "typescript: eslint --fix"

auto-commits: false
show-diffs: true


**Step 3: Symlink for Consistency**

Enter fullscreen mode Exit fullscreen mode


bash

Keep Cursor working with same rules

ln -sf AGENTS.md .cursorrules

Now both tools use identical rules


**Step 4: Test Both Tools**

Enter fullscreen mode Exit fullscreen mode


bash

Test Aider

aider --message "Add error handling to fetchUser function"

Test Cursor (open in IDE)

Both should follow same patterns


---

#### **5.3.2 Claude Code → Continue.dev Migration**

**Scenario**: Team uses Claude Code, wants to add Continue.dev for VS Code users.

**Step 1: Copy CLAUDE.md**

Enter fullscreen mode Exit fullscreen mode


bash
cp CLAUDE.md AGENTS.md


**Step 2: Create Continue.dev Config**

Enter fullscreen mode Exit fullscreen mode


yaml

.continue/config.yaml

name: team-config
version: 1.0.0
schema: v1

models:

  • name: Claude 3.5 Sonnet provider: anthropic model: claude-3-5-sonnet-20241022 apiKey: ${{ secrets.ANTHROPIC_API_KEY }} roles: [chat, edit, apply]

context:

  • provider: code
  • provider: codebase params: nRetrieve: 30 nFinal: 5

No inline rules—use markdown file instead


**Step 3: Create Continue.dev Rule File**

Enter fullscreen mode Exit fullscreen mode


markdown


name: Project Standards

alwaysApply: true

Project Standards

See AGENTS.md for complete rules.

This file exists for Continue.dev compatibility.


**Or use `chatOptions`:**

Enter fullscreen mode Exit fullscreen mode


yaml
models:

  • name: Claude 3.5 Sonnet chatOptions: baseSystemMessage: | See AGENTS.md for complete project rules. [Optionally paste key rules here]

**Step 4: Verify Both Work**

Enter fullscreen mode Exit fullscreen mode


bash

Claude Code users continue as normal

claude "Add validation to user input"

Continue.dev users (VS Code)

Open Continue panel, verify rules loaded


---

#### **5.3.3 From No Rules → Multi-Tool Setup**

**Scenario**: Project has no rules, team wants to adopt AI assistants.

**Step 1: Initial Assessment**

Enter fullscreen mode Exit fullscreen mode


bash

Answer these questions:

1. What tools does the team use?

- Cursor (3 people)

- VS Code with Continue.dev (2 people)

- Terminal/CLI with Aider (2 people)

- JetBrains with AI Assistant (1 person)

2. What are the top 5 pain points?

- Inconsistent error handling

- Mix of class/functional components

- No testing standards

- Environment variables in wrong places

- Inconsistent API response formats


**Step 2: Create Minimal AGENTS.md**

Enter fullscreen mode Exit fullscreen mode


markdown

AGENTS.md

Tech Stack

  • TypeScript, React, Node.js, PostgreSQL

Top Priority Rules

1. Error Handling

All async functions return Result:

type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };
Enter fullscreen mode Exit fullscreen mode

2. React Components

Functional components only. No classes.

3. Testing

Every feature needs tests. Run npm test before committing.

4. Environment Variables

Use .env.local (never commit secrets).

5. API Format

All endpoints return:

{
  "success": boolean,
  "data": any,
  "error": string | null
}
Enter fullscreen mode Exit fullscreen mode

**Step 3: Distribute to All Tools**

Enter fullscreen mode Exit fullscreen mode


bash
./sync-ai-rules.sh # Creates symlinks


**Step 4: 2-Week Trial**

- Team uses AI assistants for 2 weeks
- Developers note where AI gets it wrong
- Weekly team meeting to discuss friction points

**Step 5: Iterate**

Enter fullscreen mode Exit fullscreen mode


markdown

After 2 weeks, expand AGENTS.md

Additional Rules Discovered

6. State Management

  • Server state: TanStack Query
  • Client state: Zustand
  • Never: Redux (legacy, being phased out)

7. File Structure

  • Components: src/components/[feature]/[Component].tsx
  • Hooks: src/hooks/use[Feature].ts
  • Utils: src/lib/[category]/[utility].ts

8. Import Order

[Team discovered AI was mixing import order]

  1. External deps
  2. Internal packages
  3. Relative imports

**Step 6: Continuous Improvement**

Enter fullscreen mode Exit fullscreen mode


bash

Add to sprint retrospectives

"What AI patterns need clarification?"

Update AGENTS.md

Commit with team

Sync to all tools


---

### **5.4 Team Collaboration Strategies**

#### **5.4.1 Version Control Best Practices**

**What to Commit:**

Enter fullscreen mode Exit fullscreen mode


bash

✅ ALWAYS COMMIT

AGENTS.md # Master rules
.aider.conf.yml # Aider config (no secrets)
.continue/config.yaml # Continue config (no API keys)
.continue/rules/.md # Continue rule files
.cursor/rules/
.mdc # Cursor rules (not settings)
.roomodes # Roo-Cline modes
.clinerules # Cline rules
.zed/settings.json # Zed project settings (no secrets)
.aiassistant/rules/*.md # JetBrains rules

⚠️ MAYBE COMMIT (team decision)

.cursorrules # If using legacy
.windsurfrules # Windsurf rules
.github/copilot-instructions.md # Copilot rules


**What to .gitignore:**

Enter fullscreen mode Exit fullscreen mode


gitignore

❌ NEVER COMMIT

.env # Secrets
.env.local # Local environment variables
*.key # API keys
*_history # Aider history files
.aider.llm.history # LLM conversation logs

User-specific (don't commit)

.cursor/settings.json # User preferences (not rules)
.vscode/settings.json # User VS Code settings
.idea/workspace.xml # JetBrains workspace (not rules)

Generated (don't commit)

.continue/index/ # Continue.dev codebase index


**Sample `.gitignore` Addition:**

Enter fullscreen mode Exit fullscreen mode


gitignore

AI Assistant Configuration

===========================

Commit these (shared team rules)

AGENTS.md

.cursor/rules/

.continue/rules/

.aider.conf.yml

.roomodes

Don't commit these (secrets, user-specific, generated)

.env
.env.local
*.key
.aider.input.history
.aider.chat.history.md
.aider.llm.history
.cursor/settings.json
.continue/config.yaml # If it contains API keys
.continue/index/


---

#### **5.4.2 Pull Request Review Process**

**When Rules Change:**

Enter fullscreen mode Exit fullscreen mode


markdown

PR Template Addition

AI Rules Changes

  • [ ] Updated AGENTS.md with new standards
  • [ ] Synced to tool-specific locations (ran ./sync-ai-rules.sh)
  • [ ] Tested with at least 2 different AI tools
  • [ ] Documented reason for change in commit message
  • [ ] No secrets or API keys in config files

What Changed

  • [Describe rule changes]

Why

  • [Explain motivation]

Testing

  • [How you verified AI follows new rules]

**Review Checklist:**

Enter fullscreen mode Exit fullscreen mode


markdown

Reviewer Checklist: AI Rules Changes

  • [ ] Changes are clear and specific (not vague)
  • [ ] Examples included (good + bad code)
  • [ ] No conflicts with existing rules
  • [ ] No sensitive information (secrets, internal IPs, etc.)
  • [ ] Spelling and grammar correct
  • [ ] Markdown formatting valid
  • [ ] Cross-tool compatibility maintained

---

#### **5.4.3 Onboarding New Team Members**

**Day 1: Developer Onboarding Checklist**

Enter fullscreen mode Exit fullscreen mode


markdown

AI Coding Assistant Setup

Step 1: Choose Your Tool

We support:

  • Cursor (recommended for beginners)
  • Windsurf (advanced, deep reasoning)
  • VS Code + Continue.dev (free, open-source)
  • Aider (CLI-based, powerful)
  • JetBrains AI Assistant (if using IntelliJ/PyCharm)

Step 2: Install & Configure

Option A: Cursor

  1. Download Cursor: https://cursor.sh
  2. Open project folder
  3. Rules auto-load from .cursor/rules/

Option B: VS Code + Continue.dev

  1. Install Continue.dev extension
  2. Open project folder
  3. Configure API key (see team 1Password)
  4. Rules auto-load from .continue/rules/

Option C: Aider (CLI)

  1. Install: pip install aider-chat
  2. Set API key: export ANTHROPIC_API_KEY=xxx
  3. Run: aider
  4. Rules auto-load from AGENTS.md ✅

Step 3: Verify Rules Loaded

Ask your AI assistant:

"What are the top 3 coding standards for this project?"

Expected answer should mention:

  • TypeScript strict mode
  • Error handling with Result type
  • Testing requirements

If AI doesn't mention these, contact #dev-tools channel.

Step 4: Try Your First Task

Pick a good first issue labeled good-first-issue and:

  1. Ask AI to explain the codebase area
  2. Implement the fix with AI assistance
  3. Review AI's suggestions carefully
  4. Run tests before committing

Need Help?

  • Slack: #ai-coding-help
  • Docs: docs/ai-assistant-guide.md
  • Ask: @tech-lead or @ai-champion

---

#### **5.4.4 Governance for Enterprise**

**For teams 50+ developers:**

**1. Centralized Rules Repository**

Enter fullscreen mode Exit fullscreen mode

company-ai-rules/
├── universal/
│ ├── AGENTS.md # Company-wide standards
│ ├── security.md # Security requirements
│ └── compliance.md # SOC2, GDPR, etc.
├── stacks/
│ ├── typescript-react.md # React stack rules
│ ├── python-fastapi.md # Python stack rules
│ └── java-spring.md # Java stack rules
└── teams/
├── platform/ # Platform team specific
├── frontend/ # Frontend team specific
└── backend/ # Backend team specific


**2. Project Import Pattern**

Enter fullscreen mode Exit fullscreen mode


bash

In each project repo

Import company standards

curl https://raw.githubusercontent.com/company/ai-rules/main/universal/AGENTS.md > .company-standards.md

Create project-specific AGENTS.md that references it

cat > AGENTS.md << 'EOF'

Project AI Rules

Company Standards

See .company-standards.md for universal company rules.

Project-Specific Rules

[Add project-specific overrides here]
EOF


**3. Automated Compliance Checks**

Enter fullscreen mode Exit fullscreen mode


yaml

.github/workflows/ai-rules-compliance.yml

name: AI Rules Compliance

on:
pull_request:
paths:
- 'AGENTS.md'
- '.cursor/rules/'
- '.continue/rules/
'

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

  - name: Check for secrets
    run: |
      if grep -rE '(api[_-]?key|secret|password|token).*=.*[a-zA-Z0-9]{20,}' AGENTS.md .cursor .continue; then
        echo "❌ Secrets detected in rules files"
        exit 1
      fi

  - name: Validate Markdown
    run: |
      npm install -g markdownlint-cli
      markdownlint AGENTS.md

  - name: Check company standards referenced
    run: |
      if ! grep -q ".company-standards.md" AGENTS.md; then
        echo "⚠️ AGENTS.md should reference .company-standards.md"
        exit 1
      fi
Enter fullscreen mode Exit fullscreen mode

**4. AI Rules Champion Role**

Designate 1-2 people per 50 developers as "AI Rules Champions":

**Responsibilities:**
- Review PRs modifying AI rules
- Maintain company-wide standards repo
- Help teams adapt rules to their needs
- Collect feedback on rule effectiveness
- Run quarterly rules audit

**Quarterly Audit Process:**
1. Survey teams: "Which rules are most helpful? Least?"
2. Analyze AI-generated code for standards compliance
3. Update rules based on findings
4. Publish changelog and training materials

---

This completes the comprehensive multi-tool strategy guide, covering SSOT architecture, migration paths, team collaboration, and enterprise governance.

---

## **VI. Best Practices & Optimization**

### **6.1 Rule Writing Excellence**

#### **6.1.1 Specificity vs. Brevity Balance**

**The Tension:**

- ⚠️ **Too specific**: Rules become a maintenance nightmare, covering every edge case
- ⚠️ **Too brief**: AI misinterprets vague guidance, produces inconsistent code

**The Solution: The 80/20 Rule**

Focus on the **20% of patterns that solve 80% of problems**.

**Framework: Three Tiers of Specificity**

| Tier | Length | Content | When to Use |
|------|--------|---------|-------------|
| **Tier 1: Principles** | 1 sentence | High-level guideline | Always include (5-10 principles) |
| **Tier 2: Patterns** | 3-5 sentences + example | Common implementation pattern | Include 10-15 most frequent |
| **Tier 3: Edge Cases** | Detailed explanation + multiple examples | Specific gotcha or complex scenario | Include only 3-5 critical ones |

**Example Application:**

Enter fullscreen mode Exit fullscreen mode


markdown

Error Handling

Tier 1: Principle (Always Include)

All async operations must handle errors explicitly and never fail silently.

Tier 2: Pattern (Include for Common Case)

Use Result type for operations that can fail:

type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

async function operation(): Promise<Result<Data>> {
  try {
    const data = await fetch();
    return { success: true, data };
  } catch (error) {
    logger.error('Operation failed', { error });
    return { success: false, error: 'User-friendly message' };
  }
}
Enter fullscreen mode Exit fullscreen mode

Tier 3: Edge Case (Only for Critical Gotcha)

When retrying failed requests, use exponential backoff to avoid overwhelming services:

async function fetchWithRetry(url: string, maxRetries = 3): Promise<Result<Data>> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const data = await fetch(url);
      return { success: true, data };
    } catch (error) {
      if (attempt === maxRetries - 1) {
        return { success: false, error: 'Max retries exceeded' };
      }

      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

**Length Guidelines by Project Size:**

| Project Size | Total Lines | Tier 1 | Tier 2 | Tier 3 |
|--------------|------------|--------|--------|--------|
| **Small** (1-3 devs) | 150-250 | 10 principles | 10 patterns | 3 edge cases |
| **Medium** (5-15 devs) | 250-400 | 15 principles | 15 patterns | 5 edge cases |
| **Large** (15-50 devs) | 400-600 | 20 principles | 20 patterns | 8 edge cases |
| **Enterprise** (50+ devs) | 600-1000 (modular) | 25 principles | 30 patterns | 10 edge cases |

**Optimization Strategy: Start Small, Add Incrementally**

**Week 1: Minimum Viable Rules (150 lines)**
Enter fullscreen mode Exit fullscreen mode


markdown

Project Rules

Tech Stack

[Stack list]

Top 10 Principles

  1. TypeScript strict mode
  2. Result for error handling
  3. Functional React components
  4. TanStack Query for server state
  5. Zod for validation
  6. 80% test coverage
  7. Conventional Commits
  8. pnpm (not npm/yarn)
  9. No console.log in production
  10. Environment variables for config

**After 2 Weeks: Add Top 5 Patterns**
Enter fullscreen mode Exit fullscreen mode


markdown

Common Patterns

1. Error Handling

[Tier 2 example from above]

2. Component Structure

[Example]

3. API Calls

[Example]

4. Testing

[Example]

5. State Management

[Example]


**After 1 Month: Add Critical Edge Cases**
Enter fullscreen mode Exit fullscreen mode


markdown

Critical Gotchas

1. Server Component Hydration

[Tier 3 detailed explanation]

2. tRPC Context Management

[Tier 3 detailed explanation]

3. Database Transaction Deadlocks

[Tier 3 detailed explanation]


---

#### **6.1.2 The "Example-Driven" Approach**

**Research Finding**: Rules with code examples have **3.5x higher adherence** than prose-only rules.

**The Pattern: Always Pair Bad → Good**

Enter fullscreen mode Exit fullscreen mode


markdown

Rule Name

❌ WRONG (What NOT to Do)

// Bad code example
// Explain why it's bad
Enter fullscreen mode Exit fullscreen mode

Problems:

  • [Specific issue 1]
  • [Specific issue 2]

✅ CORRECT (Recommended Approach)

// Good code example
// Explain why it's better
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • [Specific benefit 1]
  • [Specific benefit 2]

**Complete Example:**

Enter fullscreen mode Exit fullscreen mode


markdown

State Management in React

❌ WRONG: Prop Drilling

// App.tsx
function App() {
  const [user, setUser] = useState<User | null>(null);
  return <Dashboard user={user} setUser={setUser} />;
}

// Dashboard.tsx
function Dashboard({ user, setUser }: Props) {
  return <Sidebar user={user} setUser={setUser} />;
}

// Sidebar.tsx
function Sidebar({ user, setUser }: Props) {
  return <UserProfile user={user} setUser={setUser} />;
}

// UserProfile.tsx (finally uses it)
function UserProfile({ user, setUser }: Props) {
  return <div>{user?.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Problems:

  • Props passed through 3 intermediate components that don't use them
  • Adding new user-related props requires updating 4 components
  • Difficult to refactor (changing prop names breaks 4 files)
  • TypeScript boilerplate for each Props interface

✅ CORRECT: Zustand Global State

// stores/userStore.ts
import { create } from 'zustand';

interface UserStore {
  user: User | null;
  setUser: (user: User | null) => void;
}

export const useUserStore = create<UserStore>((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));

// App.tsx
function App() {
  return <Dashboard />;  // No props!
}

// Dashboard.tsx
function Dashboard() {
  return <Sidebar />;  // No props!
}

// Sidebar.tsx
function Sidebar() {
  return <UserProfile />;  // No props!
}

// UserProfile.tsx (consumes directly)
function UserProfile() {
  const user = useUserStore((state) => state.user);
  const setUser = useUserStore((state) => state.setUser);

  return <div>{user?.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Components only import what they need
  • No intermediate prop passing
  • Easy to add new user-related state
  • Single source of truth
  • TypeScript inference works automatically

**Example Types by Category:**

| Category | Example Type | When to Use |
|----------|-------------|-------------|
| **Anti-Pattern** | ❌ Bad → ✅ Good | Preventing common mistakes |
| **Evolution** | Before → After | Showing refactoring improvements |
| **Comparison** | Option A vs Option B | Choosing between approaches |
| **Progression** | Basic → Intermediate → Advanced | Teaching complexity levels |
| **Context-Specific** | Server Component vs Client Component | Different contexts need different patterns |

---

#### **6.1.3 Structured Organization Patterns**

**Pattern 1: XML-Style Semantic Tags**

Enter fullscreen mode Exit fullscreen mode


markdown

Core Information

  • Stack, architecture, deployment

Style Rules

  • TypeScript, React, testing patterns

Reusable Solutions

  • Error handling, state management, API calls

Known Issues

  • Specific bugs, workarounds, edge cases

Development Process

  • Git, testing, deployment procedures

**Benefits:**
- Clear semantic boundaries
- Easy to scan (both human and AI)
- Sections independently updatable
- Natural hierarchy without deep nesting

**Pattern 2: Numbered List Hierarchy**

Enter fullscreen mode Exit fullscreen mode


markdown

1. PROJECT OVERVIEW

Brief context

2. TECHNOLOGY STACK

Detailed stack with versions

3. ARCHITECTURE

Structure and patterns

4. CODING STANDARDS

4.1 TypeScript Rules

4.1.1 Type Annotations

4.1.2 Error Handling

4.2 React Patterns

4.2.1 Component Structure

4.2.2 State Management

5. TESTING REQUIREMENTS

Coverage and patterns

6. COMMON COMMANDS

Development workflow

7. KNOWN ISSUES

Troubleshooting guide


**Benefits:**
- Clear progression (1, 2, 3...)
- Easy references ("See section 4.1.2")
- Scales to complex documentation
- Familiar structure (like technical specs)

**Pattern 3: Table-Driven Rules**

Enter fullscreen mode Exit fullscreen mode


markdown

Component Patterns

Pattern Use Case Example Avoid When
Server Component Static data, SEO-critical async function Page() Needs interactivity
Client Component Interactive UI, hooks 'use client'; useState() Pure presentation
Server Action Form submissions async function submitForm() Client-only operations
Route Handler REST API endpoints export async function POST() Type-safe APIs (use tRPC)

State Management Decision Matrix

Data Type Persistence Scope Solution Example
Server data API Component tree TanStack Query useQuery('users')
Form state Component Single form React Hook Form useForm()
UI state Component Single component useState const [open, setOpen]
Global client Memory App-wide Zustand useUserStore()
URL state URL params Route useSearchParams const [search]

**Benefits:**
- Dense information packaging
- Easy scanning for relevant row
- Forces consistent categorization
- Natural for decision-making scenarios

---

#### **6.1.4 Token Efficiency Techniques**

**Technique 1: Bullet Points Over Prose**

Enter fullscreen mode Exit fullscreen mode


markdown
❌ LOW EFFICIENCY (150 tokens):
"When you are writing TypeScript code, it is very important that you always include explicit type annotations for the return types of your functions. This helps with maintaining type safety throughout the codebase and makes it easier for other developers to understand what your functions are doing without having to read through all the implementation details."

✅ HIGH EFFICIENCY (25 tokens):
TypeScript Rules:

  • Explicit return types required on all functions
  • Improves type safety and code readability
  • Example: function calc(x: number): number { return x * 2; }

**Technique 2: Code Examples > Explanations**

Enter fullscreen mode Exit fullscreen mode


markdown
❌ VERBOSE (200 tokens):
"For error handling in asynchronous operations, you should use a pattern where you wrap the return value in an object that has a success boolean property to indicate whether the operation succeeded or failed. If it succeeded, include the data in a data property. If it failed, include an error message in an error property. This makes it easy to check if an operation succeeded and handle errors appropriately without using try-catch blocks everywhere."

✅ CONCISE (75 tokens):
Error Handling:

type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };

// Usage
const result = await fetchUser(id);
if (!result.success) {
  return handleError(result.error);
}
const user = result.data;
Enter fullscreen mode Exit fullscreen mode

**Technique 3: Tables for Mappings**

Enter fullscreen mode Exit fullscreen mode


markdown
❌ PROSE (180 tokens):
"When you need to fetch server data, use TanStack Query. When you're managing form state, use React Hook Form. For simple component-level state like whether a modal is open, use useState. If you need global client state that persists across the app, use Zustand. When state needs to be in the URL, use Next.js useSearchParams."

✅ TABLE (60 tokens):
| Need | Solution |
|------|----------|
| Server data | TanStack Query |
| Form state | React Hook Form |
| Local state | useState |
| Global state | Zustand |
| URL state | useSearchParams |


**Technique 4: Eliminate Filler Words**

Enter fullscreen mode Exit fullscreen mode


markdown
❌ WORDY:
"I would really appreciate it if you could make sure to always validate user inputs"

✅ DIRECT:
"ALWAYS validate user inputs"

❌ WORDY:
"It's generally considered a good practice to prefer composition over inheritance"

✅ DIRECT:
"Prefer composition over inheritance"

❌ WORDY:
"When you're working on this particular codebase, please try to remember that"

✅ DIRECT:
"Remember:"


**Token Savings Comparison:**

| Original Length | Optimized Length | Savings |
|----------------|------------------|---------|
| 1000 tokens (prose-heavy) | 350 tokens (optimized) | 65% |
| 500 tokens (moderate) | 250 tokens (optimized) | 50% |
| 300 tokens (concise) | 200 tokens (optimized) | 33% |

---

### **6.2 Testing and Validation**

#### **6.2.1 The "Gold Standard" Test**

**Method: Delete and Regenerate**

**Purpose**: Verify AI can recreate existing code following your rules.

**Process**:

1. **Select target**: Choose a representative function/component
2. **Document expected behavior**: Note what it should do
3. **Delete the code**: Completely remove implementation
4. **Prompt AI**: "Implement [function name] based on project rules"
5. **Compare**: Diff AI output against original
6. **Score**: Calculate similarity percentage

**Scoring Rubric**:

| Aspect | Weight | Score Calculation |
|--------|--------|-------------------|
| **Functionality** | 40% | Does it work correctly? (0-10) |
| **Style Match** | 30% | Follows coding standards? (0-10) |
| **Patterns** | 20% | Uses correct patterns (error handling, state, etc.)? (0-10) |
| **Structure** | 10% | File organization, imports, naming? (0-10) |

**Total Score** = (Functionality × 0.4) + (Style × 0.3) + (Patterns × 0.2) + (Structure × 0.1)

**Interpretation**:
- **90-100%**: Excellent rules—AI perfectly replicates codebase style
- **70-89%**: Good rules—minor adjustments needed
- **50-69%**: Adequate rules—significant gaps exist
- **< 50%**: Poor rules—major revision required

**Example Test**:

Enter fullscreen mode Exit fullscreen mode


typescript
// Original code (before deletion)
async function fetchUserProfile(userId: string): Promise> {
try {
const profile = await db.query.userProfiles.findFirst({
where: eq(userProfiles.userId, userId),
with: {
user: true,
posts: {
limit: 10,
orderBy: desc(posts.createdAt)
}
}
});

if (!profile) {
  return { success: false, error: 'Profile not found' };
}

return { success: true, data: profile };
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
logger.error('fetchUserProfile failed', { userId, error });
return { success: false, error: 'Failed to fetch profile' };
}
}

// Delete code, prompt AI:
// "Implement fetchUserProfile function that:
// - Takes userId (string)
// - Fetches user profile with related user and latest 10 posts
// - Returns Result type
// - Handles not found and errors appropriately"

// AI generates:
async function fetchUserProfile(userId: string): Promise> {
try {
const profile = await db.query.userProfiles.findFirst({
where: eq(userProfiles.userId, userId),
with: {
user: true,
posts: {
limit: 10,
orderBy: desc(posts.createdAt)
}
}
});

if (!profile) {
  return { success: false, error: 'Profile not found' };
}

return { success: true, data: profile };
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
logger.error('fetchUserProfile failed', { userId, error });
return { success: false, error: 'Failed to fetch profile' };
}
}

// Result: 100% match! Rules are working perfectly.


---

#### **6.2.2 Violation Prompt Technique**

**Method: Self-Review**

Ask AI to critique your rules for contradictions and ambiguities.

**Prompt Template**:

Enter fullscreen mode Exit fullscreen mode

Review the AI coding rules in [FILENAME].

Identify:

  1. Contradictions (rules that conflict with each other)
  2. Ambiguities (vague rules that could be interpreted multiple ways)
  3. Missing critical information (patterns not covered)
  4. Overly prescriptive rules (too specific, limiting flexibility)
  5. Outdated information (deprecated libraries/patterns)

For each issue, provide:

  • Location (section/line)
  • Description of problem
  • Suggested fix
  • Priority (High/Medium/Low)

**Example AI Response**:

Enter fullscreen mode Exit fullscreen mode


markdown

Contradictions

Issue 1: State Management Conflict (HIGH PRIORITY)

Location: Section 4.2.2 "State Management" and Section 7.3 "Known Issues"

Problem:

  • Section 4.2.2 says: "Use Context API for global state"
  • Section 7.3 says: "Context API causes performance issues, use Zustand"

Fix: Remove Context API recommendation from 4.2.2, consolidate on Zustand.

Issue 2: Component Size Limits (MEDIUM PRIORITY)

Location: Section 4.1 "Component Rules"

Problem:

  • One rule says: "Maximum 200 lines per component"
  • Another says: "Keep components under 150 lines"

Fix: Pick one limit (recommend 200 lines) and remove the other.

Ambiguities

Issue 3: "Modern JavaScript" Undefined (HIGH PRIORITY)

Location: Section 3.1 "Language Standards"

Problem: Rule states "Use modern JavaScript" without defining what that means.

Fix: Be specific:

## Modern JavaScript (ES2022+)
- ✅ Use: async/await, optional chaining `?.`, nullish coalescing `??`
- ❌ Avoid: `.then()` chains, `|| ` for defaults, var declarations
Enter fullscreen mode Exit fullscreen mode

Issue 4: Testing "Should" vs "Must" (MEDIUM PRIORITY)

Location: Section 5 "Testing Requirements"

Problem: Uses weak language "should write tests" instead of requirements.

Fix: Use clear directives:

  • "REQUIRED: All business logic functions must have unit tests"
  • "REQUIRED: All API endpoints must have integration tests"
  • "OPTIONAL: E2E tests for critical flows"

Missing Information

Issue 5: No Database Migration Strategy (HIGH PRIORITY)

Location: Missing from entire document

Problem: No guidance on creating or managing database migrations.

Fix: Add section:

## Database Migrations

- Use Drizzle Kit for schema changes: `pnpm db:generate`
- Never edit migration files manually
- Test migrations on staging before production
- Always include rollback strategy
Enter fullscreen mode Exit fullscreen mode

Issue 6: No Environment Setup Instructions (MEDIUM PRIORITY)

Location: Missing

Fix: Add section on .env.local setup, required variables, validation.

Overly Prescriptive

Issue 7: Hardcoded File Locations (LOW PRIORITY)

Location: Section 4.3 "File Structure"

Problem: Rules specify exact file names: "Put API utils in /lib/api/utils.ts"

Fix: Use patterns instead: "Organize API utilities in /lib/api/ directory"

Outdated Information

Issue 8: Next.js Pages Router References (HIGH PRIORITY)

Location: Section 2 "Tech Stack" and Section 4 "Routing"

Problem: Mentions "pages directory" but project uses App Router.

Fix: Remove all Pages Router references, update to App Router patterns.


---

#### **6.2.3 Effectiveness Metrics**

**Metric 1: AI Adherence Rate**

**Definition**: Percentage of AI-generated code that follows project rules without modification.

**Measurement**:
1. Over 1 week, track all AI code generations (20-50 samples)
2. For each, manually review: Does it follow rules? (Yes/Partial/No)
3. Calculate: `(Yes × 1 + Partial × 0.5 + No × 0) / Total`

**Target**: >90% adherence

**Example Tracking Sheet**:

| Date | Task | Tool | Adherence | Notes |
|------|------|------|-----------|-------|
| 11-25 | Add API endpoint | Cursor | Yes (100%) | Perfect Result<T> usage |
| 11-25 | Create component | Windsurf | Partial (50%) | Used functional but no types |
| 11-26 | Fix bug | Aider | Yes (100%) | Correct error handling |
| 11-26 | Write tests | Cline | No (0%) | Used Jest instead of Vitest |

**Analysis**: 62.5% adherence—rules need clarification on testing framework.

---

**Metric 2: Code Review Iteration Count**

**Definition**: Average number of review cycles needed for AI-generated code.

**Measurement**:
1. Track PRs containing AI-generated code
2. Count review cycles (requested changes) before merge
3. Compare to baseline (non-AI code)

**Calculation**:
Enter fullscreen mode Exit fullscreen mode

AI Code Review Cycles = Total review cycles / Number of AI-assisted PRs
Baseline Cycles = Total review cycles / Number of manual PRs

Efficiency = (Baseline - AI) / Baseline × 100%


**Example**:
- **Before rules**: AI code averaged 3.5 review cycles (vs 2.1 baseline)
- **After rules**: AI code averaged 1.8 review cycles (vs 2.1 baseline)
- **Improvement**: AI code now 14% better than manual!

---

**Metric 3: Standards Compliance Score**

**Definition**: Automated check of code against project standards.

**Tools**:
- **Linters**: ESLint, Ruff, etc.
- **Type checkers**: TypeScript, mypy
- **Formatters**: Prettier, Black
- **Custom scripts**: Regex checks for patterns

**Measurement**:
Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

compliance-check.sh

Run linter

eslint_errors=$(pnpm lint --format json | jq '.[] | .errorCount' | awk '{s+=$1} END {print s}')

Run type checker

tsc_errors=$(pnpm type-check 2>&1 | grep -c "error TS")

Check for anti-patterns

console_logs=$(grep -r "console.log" src/ --exclude-dir=node_modules | wc -l)
any_types=$(grep -r ": any" src/ --exclude-dir=node_modules | wc -l)

Calculate score (lower is better)

total_violations=$((eslint_errors + tsc_errors + console_logs + any_types))

echo "Compliance Violations: $total_violations"

if [ $total_violations -eq 0 ]; then
echo "✅ 100% compliant"
exit 0
elif [ $total_violations -lt 10 ]; then
echo "⚠️ Mostly compliant"
exit 0
else
echo "❌ Poor compliance"
exit 1
fi


**Target**: 0 violations (100% compliant)

---

**Metric 4: Onboarding Time**

**Definition**: Time for new developer to become productive with AI assistant.

**Measurement**:
1. **Without rules**: Track time to first merged PR
2. **With rules**: Track time to first merged PR
3. **Calculate reduction**

**Example**:
- **Before rules**: Average 2.5 weeks to first merge
- **After rules**: Average 4 days to first merge
- **Improvement**: 84% faster onboarding!

---

**Metric 5: Bug Rate in AI-Generated Code**

**Definition**: Bugs per 1000 lines of AI-generated code.

**Measurement**:
1. Tag commits with AI involvement (`Co-authored-by: AI`)
2. Track bugs linked to those commits
3. Calculate: `Bugs / (Lines of AI code / 1000)`

**Target**: Equal to or better than manually written code

---

#### **6.2.4 Automated Validation Scripts**

**Script 1: Rules Freshness Check**

Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

check-rules-freshness.sh

Check if rules have been updated recently

RULES_FILE="AGENTS.md"
DAYS_THRESHOLD=90 # Flag if not updated in 90 days

last_modified=$(git log -1 --format=%ct $RULES_FILE)
now=$(date +%s)
days_old=$(( ($now - $last_modified) / 86400 ))

if [ $days_old -gt $DAYS_THRESHOLD ]; then
echo "⚠️ $RULES_FILE is $days_old days old (>$DAYS_THRESHOLD)"
echo "Consider reviewing for outdated information"
exit 1
else
echo "✅ $RULES_FILE is current ($days_old days old)"
exit 0
fi


---

**Script 2: Cross-Tool Sync Validation**

Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

check-rules-sync.sh

Verify all tool-specific rule files are in sync with AGENTS.md

MASTER="AGENTS.md"
TOOLS=(.rules .cursorrules .windsurfrules .clinerules CLAUDE.md)

for tool in "${TOOLS[@]}"; do
if [ -L "$tool" ]; then
# It's a symlink - verify target
target=$(readlink "$tool")
if [ "$target" = "$MASTER" ]; then
echo "✅ $tool → $MASTER (symlink OK)"
else
echo "❌ $tool → $target (should point to $MASTER)"
exit 1
fi
elif [ -f "$tool" ]; then
# It's a file - check if identical
if diff -q "$tool" "$MASTER" > /dev/null; then
echo "✅ $tool matches $MASTER (content identical)"
else
echo "⚠️ $tool differs from $MASTER (may need sync)"
exit 1
fi
else
echo "ℹ️ $tool not found (optional)"
fi
done

echo "✅ All tool configurations synced"


---

**Script 3: Forbidden Pattern Detector**

Enter fullscreen mode Exit fullscreen mode


bash

!/bin/bash

detect-anti-patterns.sh

Check AI-generated code for anti-patterns

VIOLATIONS=0

Check for console.log in production code

console_logs=$(grep -r "console\.log" src/ --exclude-dir=node_modules | wc -l)
if [ $console_logs -gt 0 ]; then
echo "❌ Found $console_logs console.log statements"
grep -r "console.log" src/ --exclude-dir=node_modules
VIOLATIONS=$((VIOLATIONS + console_logs))
fi

Check for 'any' types

any_types=$(grep -r ": any" src/ --exclude-dir=node_modules --include=".ts" --include=".tsx" | wc -l)
if [ $any_types -gt 0 ]; then
echo "❌ Found $any_types uses of 'any' type"
grep -r ": any" src/ --exclude-dir=node_modules --include=".ts" --include=".tsx"
VIOLATIONS=$((VIOLATIONS + any_types))
fi

Check for .then() chains (prefer async/await)

then_chains=$(grep -r ".then(" src/ --exclude-dir=node_modules --include=".ts" --include=".tsx" | wc -l)
if [ $then_chains -gt 0 ]; then
echo "⚠️ Found $then_chains .then() chains (prefer async/await)"
VIOLATIONS=$((VIOLATIONS + then_chains))
fi

Check for class components (prefer functional)

class_components=$(grep -r "extends React.Component" src/ --exclude-dir=node_modules | wc -l)
if [ $class_components -gt 0 ]; then
echo "❌ Found $class_components class components (use functional)"
VIOLATIONS=$((VIOLATIONS + class_components))
fi

echo ""
if [ $VIOLATIONS -eq 0 ]; then
echo "✅ No anti-patterns detected"
exit 0
else
echo "❌ Total violations: $VIOLATIONS"
exit 1
fi


---

**Script 4: CI Integration**

Enter fullscreen mode Exit fullscreen mode


yaml

.github/workflows/ai-rules-check.yml

name: AI Rules Validation

on:
pull_request:
paths:
- 'AGENTS.md'
- '.cursor/rules/'
- '.continue/rules/
'
- 'src/**'

jobs:
validate-rules:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Full history for git log checks

  - name: Check rules freshness
    run: ./scripts/check-rules-freshness.sh

  - name: Check cross-tool sync
    run: ./scripts/check-rules-sync.sh

  - name: Detect anti-patterns
    run: ./scripts/detect-anti-patterns.sh

  - name: Check for secrets in rules
    run: |
      if grep -rE '(api[_-]?key|secret|password|token).*=.*[a-zA-Z0-9]{20,}' AGENTS.md; then
        echo "❌ Secrets detected in AGENTS.md"
        exit 1
      fi

  - name: Validate Markdown syntax
    run: |
      npm install -g markdownlint-cli
      markdownlint AGENTS.md .cursor/rules/ .continue/rules/
Enter fullscreen mode Exit fullscreen mode

---

### **6.3 Maintenance Lifecycle**

#### **6.3.1 Update Frequency Guidelines**

**Update Triggers**:

| Trigger | Frequency | Scope | Example |
|---------|-----------|-------|---------|
| **Critical Bug** | Immediate | Single rule fix | AI repeatedly generates insecure code |
| **Stack Upgrade** | Within 1 week | Tech stack section | Next.js 14 → 15, new patterns |
| **Pattern Discovery** | Weekly | Add 1-2 rules | Team discovers better error handling |
| **Major Refactor** | After completion | Architecture section | Migrating to microservices |
| **Quarterly Review** | Every 3 months | Full document | Remove outdated, consolidate duplicates |

**Update Schedule Template**:

Enter fullscreen mode Exit fullscreen mode


markdown

AGENTS.md Maintenance Schedule

Weekly (Fridays, 30 minutes)

  • [ ] Review AI-generated code from this week
  • [ ] Identify patterns AI got wrong
  • [ ] Add 1-2 clarifying rules
  • [ ] Test with "Gold Standard" regeneration

Monthly (Last Friday, 2 hours)

  • [ ] Review all rules for relevance
  • [ ] Remove deprecated patterns
  • [ ] Update library versions
  • [ ] Check for contradictions (violation prompt)
  • [ ] Update examples with latest syntax

Quarterly (End of Q1/Q2/Q3/Q4, 4 hours)

  • [ ] Full document review with team
  • [ ] Major version bump (1.0 → 2.0)
  • [ ] Reorganize structure if needed
  • [ ] Archive old versions
  • [ ] Run effectiveness metrics analysis
  • [ ] Team retrospective: "What's working? What's not?"

On-Demand (As needed)

  • [ ] Stack upgrade (framework, language, major library)
  • [ ] Architecture change
  • [ ] Critical bug in AI generations
  • [ ] New team member feedback

---

#### **6.3.2 Version Control for Rules**

**Semantic Versioning**:

Enter fullscreen mode Exit fullscreen mode

MAJOR.MINOR.PATCH

Example: 2.3.1

MAJOR (2): Breaking changes (e.g., complete tech stack change)
MINOR (3): New rules added (e.g., new pattern introduced)
PATCH (1): Clarifications/fixes (e.g., typo, example correction)


**Version Header in AGENTS.md**:

Enter fullscreen mode Exit fullscreen mode


markdown

AGENTS.md

Version: 2.3.1

Last Updated: 2025-11-29

Breaking Changes Since 2.0: None

Compatible With: Cursor, Windsurf, Claude Code, Aider, Continue.dev, Cline, Zed


Changelog

2.3.1 (2025-11-29)

Changed:

  • Clarified Server Component usage in Section 4.2
  • Added example for hybrid hydration pattern
  • Fixed typo in error handling section

2.3.0 (2025-11-15)

Added:

  • New section on database transaction patterns
  • Testing strategies for tRPC procedures
  • Deployment checklist

2.2.0 (2025-10-30)

Changed:

  • Migrated from Redux to Zustand (MAJOR pattern change)
  • Updated all state management examples
  • Removed Redux-specific rules

Deprecated:

  • Redux patterns (see migration guide in docs/)

2.1.0 (2025-09-20)

Added:

  • React 19 patterns
  • Server Actions guidelines

2.0.0 (2025-08-01) - BREAKING

Changed:

  • Migrated from Pages Router to App Router
  • Complete Next.js section rewrite
  • File structure patterns updated

Migration Guide: See docs/migration-2.0.md


---

**Git Tagging Strategy**:

Enter fullscreen mode Exit fullscreen mode


bash

Tag major releases

git tag -a v2.0.0 -m "AGENTS.md v2.0.0: Next.js App Router migration"
git push origin v2.0.0

View version history

git tag -l "v*" --format="%(refname:short) - %(contents:subject)"

Compare versions

git diff v2.0.0 v2.3.1 -- AGENTS.md

Restore previous version if needed

git show v2.0.0:AGENTS.md > AGENTS.md.backup


---

#### **6.3.3 Deprecation Strategies**

**Pattern: Dual-Track Migration**

Enter fullscreen mode Exit fullscreen mode


markdown

State Management

Current Standard (Use This)

Use Zustand for global client state:

import { create } from 'zustand';

export const useUserStore = create<UserStore>((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));
Enter fullscreen mode Exit fullscreen mode

Deprecated (Migrate Away)

⚠️ DEPRECATED as of v2.2.0 (2025-10-30)

Redux is being phased out. See migration guide: docs/redux-to-zustand.md

For existing Redux code:

  • ✅ Do: Maintain existing files
  • ❌ Don't: Create new Redux slices
  • 🔄 Migrate: When touching Redux code, consider converting to Zustand

Timeline:

  • Now: Zustand for all new code
  • Q1 2026: Begin systematic Redux removal
  • Q2 2026: Complete migration (Redux fully removed)

---

**Pattern: Warning Labels**

Enter fullscreen mode Exit fullscreen mode


markdown

Component Patterns

⚠️ LEGACY: Class Components

// This pattern still exists in codebase but is deprecated
class UserProfile extends React.Component {
  render() {
    return <div>{this.props.user.name}</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

Status: Deprecated since v2.0.0 (2025-08-01)

Action: Convert to functional components when touched

Remaining: ~15 class components (tracked in issue #234)

✅ CURRENT: Functional Components

// Use this pattern for all new code
function UserProfile({ user }: Props) {
  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

---

**Pattern: Migration Notices**

Enter fullscreen mode Exit fullscreen mode


markdown

Breaking Changes in v2.0.0

Next.js App Router Migration

What Changed:

  • pages/ directory → app/ directory
  • getServerSideProps → Server Components
  • _app.tsxlayout.tsx

Migration Examples:

Before (Pages Router)

// pages/users/[id].tsx
export async function getServerSideProps({ params }) {
  const user = await fetchUser(params.id);
  return { props: { user } };
}

export default function UserPage({ user }) {
  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

After (App Router)

// app/users/[id]/page.tsx
export default async function UserPage({ params }) {
  const user = await fetchUser(params.id);  // Direct fetch
  return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Full Migration Guide: docs/app-router-migration.md


---

#### **6.3.4 Context Engineering Refinement**

**Evolution Process**:

**Phase 1: Weak Rule (Initial)**
Enter fullscreen mode Exit fullscreen mode


markdown
Follow good error handling practices.


**Result**: AI produces inconsistent approaches.

---

**Phase 2: Explicit Directive (Iteration 1)**
Enter fullscreen mode Exit fullscreen mode


markdown
Always handle errors in async functions.


**Result**: AI adds try-catch but error handling varies.

---

**Phase 3: Pattern Specification (Iteration 2)**
Enter fullscreen mode Exit fullscreen mode


markdown
Use Result type for error handling:

type Result<T> = 
  | { success: true; data: T }
  | { success: false; error: string };
Enter fullscreen mode Exit fullscreen mode

Result: AI uses Result but logger not always called.


Phase 4: Complete Template (Final)

## Error Handling Pattern (REQUIRED)

ALL async operations MUST follow this exact pattern:

Enter fullscreen mode Exit fullscreen mode


typescript
async function operationName(params): Promise> {
try {
// 1. Perform operation
const result = await performOperation(params);

// 2. Validate result
if (!result) {
  return { success: false, error: 'Human-readable error message' };
}

// 3. Return success
return { success: true, data: result };
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
// 4. ALWAYS log with context
logger.error('operationName failed', { params, error });

// 5. Return user-friendly error
return { success: false, error: 'Operation failed' };
Enter fullscreen mode Exit fullscreen mode

}
}


**Checklist for every async function**:
- [ ] Returns `Promise<Result<T>>`
- [ ] Has try-catch block
- [ ] Logs errors with context
- [ ] Returns user-friendly error messages
- [ ] Validates result before returning
Enter fullscreen mode Exit fullscreen mode

Result: 98% adherence achieved.


Strengthening Techniques:

1. Use XML Tags for Emphasis

<CRITICAL>
NEVER commit secrets or API keys to git.
ALWAYS use environment variables.
</CRITICAL>
Enter fullscreen mode Exit fullscreen mode

2. Use CAPS for Requirements

REQUIRED: All public functions MUST have JSDoc comments.
FORBIDDEN: Using `any` type without explicit justification comment.
Enter fullscreen mode Exit fullscreen mode

3. Add Verification Steps

## Before Committing

Verify your changes:
1. Run `pnpm lint` (must pass with 0 warnings)
2. Run `pnpm type-check` (must pass with 0 errors)
3. Run `pnpm test` (all tests must pass)
4. Check for console.log statements (must be removed)
5. Verify no secrets in diff (must use .env)

If ANY check fails, DO NOT commit.
Enter fullscreen mode Exit fullscreen mode

6.4 Advanced Patterns

6.4.1 Modularization for Scale

Pattern: Core + Domain Split

my-project/
├── AI_RULES_CORE.md                    # Universal standards (500 lines)
├── AI_RULES_FRONTEND.md                # React/Next.js specific (300 lines)
├── AI_RULES_BACKEND.md                 # API/Database specific (300 lines)
├── AI_RULES_TESTING.md                 # Testing strategies (200 lines)
└── AGENTS.md                           # Master file (imports others)
Enter fullscreen mode Exit fullscreen mode

AGENTS.md (Master File):

# AGENTS.md - Project AI Rules

**Version**: 3.0.0  
**Last Updated**: 2025-11-29  

---

## Quick Start

This file references modular rule documents:

- **Core Standards** (all developers): See AI_RULES_CORE.md
- **Frontend Development** (React/Next.js): See AI_RULES_FRONTEND.md
- **Backend Development** (API/Database): See AI_RULES_BACKEND.md
- **Testing** (QA/TDD): See AI_RULES_TESTING.md

---

## Critical Rules (Always Apply)

1. **Never commit secrets** (use environment variables)
2. **Result<T> for error handling** (see Core)
3. **80% test coverage minimum** (see Testing)
4. **TypeScript strict mode** (see Core)
5. **Functional React components** (see Frontend)

---

## How to Use

### For AI Assistants

**Cursor**: Create symlinks in `.cursor/rules/`
Enter fullscreen mode Exit fullscreen mode


bash
ln -s ../../AI_RULES_CORE.md .cursor/rules/01-core.mdc
ln -s ../../AI_RULES_FRONTEND.md .cursor/rules/02-frontend.mdc


**Aider**: Load multiple files
Enter fullscreen mode Exit fullscreen mode


yaml

.aider.conf.yml

read:

  • AI_RULES_CORE.md
  • AI_RULES_FRONTEND.md
  • AI_RULES_BACKEND.md
  • AI_RULES_TESTING.md

**Continue.dev**: Reference in rules
Enter fullscreen mode Exit fullscreen mode


markdown

See:

  • @AI_RULES_CORE.md
  • @AI_RULES_FRONTEND.md
  • @AI_RULES_BACKEND.md

---

## Full Documentation

For complete rules, read all referenced files above.
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • ✅ Specialists load only relevant rules (lower token usage)
  • ✅ Easier to maintain (change frontend rules without touching backend)
  • ✅ Clear ownership (frontend team owns AI_RULES_FRONTEND.md)
  • ✅ Faster updates (smaller files = quicker edits)

6.4.2 Multi-Agent Coordination

Pattern: Agent-Specific Instructions

Scenario: Team uses multiple AI agents for different tasks.

AGENTS.md with Role-Based Sections:

# Multi-Agent Coordination

## Role: Architect Agent

**Use When**: Planning new features, designing system architecture, making technology decisions.

**Responsibilities**:
- Create architecture decision records (ADRs)
- Generate system design documents
- Propose 2-3 solution options with trade-offs
- Create Mermaid diagrams

**Constraints**:
- DO NOT implement code (only design)
- DO NOT make unilateral decisions (present options)
- MUST document in `docs/adr/`

**Output Format**:
Enter fullscreen mode Exit fullscreen mode


markdown

ADR-XXX: [Decision Title]

Status

Proposed

Context

[Problem being solved]

Options

Option 1: [Approach]

Pros: ...
Cons: ...

Option 2: [Approach]

Pros: ...
Cons: ...

Decision

[Chosen option with justification]

Consequences

[Implications of decision]


---

## Role: Implementation Agent

**Use When**: Writing production code, refactoring, fixing bugs.

**Responsibilities**:
- Implement features following ADRs
- Write tests alongside code (TDD)
- Handle errors with Result<T> pattern
- Create typed, documented code

**Constraints**:
- MUST follow architecture from ADRs
- MUST write tests before marking complete
- MUST run linter before finishing
- CAN NOT change architecture (escalate to Architect)

**Verification Checklist**:
- [ ] Code follows TypeScript strict mode
- [ ] All functions have explicit return types
- [ ] Tests written and passing
- [ ] Error handling with Result<T>
- [ ] No console.log statements
- [ ] Linter passes with 0 warnings

---

## Role: Testing Agent

**Use When**: Writing comprehensive test suites, improving test coverage.

**Responsibilities**:
- Write unit, integration, and E2E tests
- Achieve 80%+ coverage
- Use Vitest for unit, Playwright for E2E
- Follow AAA pattern (Arrange, Act, Assert)

**Constraints**:
- DO NOT modify production code (only tests)
- MUST test happy path + error cases + edge cases
- MUST mock external dependencies
- CAN NOT skip tests "to save time"

**Test Template**:
Enter fullscreen mode Exit fullscreen mode


typescript
describe('FeatureName', () => {
describe('Happy Path', () => {
it('should succeed with valid input', async () => {
// Arrange
const input = createValidInput();

  // Act
  const result = await operation(input);

  // Assert
  expect(result.success).toBe(true);
  expect(result.data).toMatchObject(expected);
});
Enter fullscreen mode Exit fullscreen mode

});

describe('Error Cases', () => {
it('should handle invalid input', async () => {
const result = await operation(invalidInput);
expect(result.success).toBe(false);
expect(result.error).toContain('validation');
});
});

describe('Edge Cases', () => {
it('should handle empty input', async () => {
const result = await operation([]);
expect(result.success).toBe(true);
expect(result.data).toEqual([]);
});
});
});


---

## Role: Code Reviewer

**Use When**: Reviewing PRs, checking for issues, suggesting improvements.

**Responsibilities**:
- Review code for standards compliance
- Check for security vulnerabilities
- Verify test coverage
- Suggest performance improvements

**Constraints**:
- DO NOT implement fixes (only suggest)
- MUST explain reasoning for suggestions
- MUST prioritize suggestions (Critical/High/Medium/Low)
- CAN NOT approve without verification

**Review Checklist**:
Enter fullscreen mode Exit fullscreen mode


markdown

Security

  • [ ] No hardcoded secrets
  • [ ] Input validation present
  • [ ] SQL injection prevention (parameterized queries)
  • [ ] XSS prevention (React auto-escapes)

Code Quality

  • [ ] TypeScript strict mode compliant
  • [ ] Explicit return types
  • [ ] Error handling with Result
  • [ ] No code duplication (DRY)

Testing

  • [ ] Tests present and passing
  • [ ] Coverage >80%
  • [ ] Edge cases covered

Performance

  • [ ] No unnecessary re-renders (React)
  • [ ] Efficient algorithms (no O(n²) unless necessary)
  • [ ] Database queries optimized (no N+1)
Enter fullscreen mode Exit fullscreen mode

Usage:

# Architect session
ai-agent --role architect "Design authentication system"

# Implementation session
ai-agent --role implementation "Implement user registration following ADR-005"

# Testing session
ai-agent --role testing "Write comprehensive tests for authentication"

# Review session
ai-agent --role reviewer "Review PR #42 for security and standards"
Enter fullscreen mode Exit fullscreen mode

6.4.3 Dynamic Rules Systems

Pattern: File-Trigger-Based Context Loading

Advanced Roo-Cline Example:

# .roomodes

customModes:
  # Auto-switch based on file type
  - slug: react-components
    name: React Component Specialist
    roleDefinition: Expert in React 19 component development
    groups:
      - read
      - - edit
        - fileRegex: components/.*\.(tsx|jsx)$

    customInstructions: |-
      ## Component-Specific Rules
      [Detailed React rules]

  - slug: database-operations
    name: Database Specialist
    roleDefinition: Expert in Drizzle ORM and PostgreSQL
    groups:
      - read
      - - edit
        - fileRegex: (lib/db/|.*\.schema\.ts)

    customInstructions: |-
      ## Database Rules
      [Detailed database rules]

  - slug: api-endpoints
    name: API Developer
    roleDefinition: Expert in tRPC procedures and API design
    groups:
      - read
      - - edit
        - fileRegex: lib/api/.*\.ts

    customInstructions: |-
      ## API Rules
      [Detailed API rules]
Enter fullscreen mode Exit fullscreen mode

Benefit: AI automatically gets context-appropriate rules based on which files you're editing.


Pattern: Real-Time Rule Updates

Conceptual (Future Feature):

# AGENTS.md with Update Triggers

## Real-Time Update System

### Pattern Discovery Trigger
When you discover a new pattern:
1. Press `#` key (Claude Code)
2. Or use `/add-rule` command
3. AI proposes rule addition
4. You approve/edit
5. AGENTS.md updated automatically

### Error Pattern Trigger
When AI makes the same mistake 3 times:
1. System detects pattern
2. Proposes clarifying rule
3. You approve
4. Rule added with examples

### Contradiction Detection Trigger
When new rule conflicts with existing:
1. System highlights conflict
2. Proposes resolution
3. You choose approach
4. Conflicting rules reconciled
Enter fullscreen mode Exit fullscreen mode

This comprehensive Best Practices & Optimization section provides everything needed to write effective rules, test their effectiveness, maintain them over time, and implement advanced patterns for scaling to complex multi-agent, multi-tool environments.

The guide is now complete with actionable strategies backed by real-world examples and measurable metrics.

Top comments (0)