DEV Community

Yigit Konur
Yigit Konur

Posted on

How to Set Rules for AI Coding Agents: Prompt Engineering Tips & Tricks from a Prompt Engineer

Combining cognitive science, prompt engineering, and practical templates for any AI coding tool


Introduction

After analyzing thousands of AI coding sessions and refining instructions across enterprise teams and startups, one truth emerges: 90% of teams write their AI rules wrong.

Not because they're bad developers, but because they treat AI instructions like human documentation.

The Core Insight: Humans read documentation to build mental models. AI agents read instructions to execute patterns.

This guide teaches you how to write instructions that make AI coding agents dramatically more effective—regardless of which tool you use (Cursor, Windsurf, Claude Code, Aider, etc.).

What you'll learn:

  • The cognitive architecture of how AI agents process instructions
  • The 7 principles that produce 90%+ AI adherence rates
  • Universal patterns that work across all AI coding tools
  • Battle-tested prompt engineering techniques with before/after examples
  • Template structures you can copy-paste and customize
  • How to measure and improve rule effectiveness

Core Principle: AI coding agents are context processors, not mind readers. Your instructions are the lens through which they interpret your codebase. Bad instructions = inconsistent, incorrect code. Good instructions = AI that behaves like a senior engineer who knows your project intimately.


Part I: Understanding How AI Agents Process Instructions

The Token Economics of AI Attention

Every AI coding agent operates under a fundamental constraint: context window limits.

Modern AI Context Windows:

AI Models Comparison Tables

Table 1: Context Window & Pricing Overview

Model Release Date Context Window Max Input Max Output Input Price (per 1M tokens) Output Price (per 1M tokens)
Gemini 3 Pro Nov 2025 2M 2M Variable $0.35-$2.50 $1.05-$15
Gemini 3 (base) Nov 2025 2M 2M Variable $0.35-$2.50 $1.05-$15
Claude Sonnet 4.5 Sep 2025 200K 200K 32K $3 $15
Claude Opus 4.5 Nov 2025 200K 200K 32K $15 $75
GPT-5.1 Nov 12, 2025 400K 400K Variable $1.25 $10
GPT-5.1 Auto Nov 12, 2025 400K 400K Variable $1.25 $10
GPT-5.1-Codex-Max Nov 19, 2025 400K+ 400K+ Variable $1.25 $10
Grok 4 Jul 2025 128K-1M 128K-1M Variable $0.20 $0.50
Grok 4.1 Nov 16, 2025 1M+ 1M+ Variable $0.20 $0.50
Grok 4.1 Fast Nov 20, 2025 1M 1M Variable $0.20 $0.50

Table 2: Coding Benchmarks & Pricing

Model Coding Benchmark Score/Performance Input Price (per 1M tokens) Output Price (per 1M tokens) Notable Features
Gemini 3 Pro HumanEval 90%+ $0.35-$2.50 $1.05-$15 Autonomous coding agents, lower latency
Claude Sonnet 4.5 SWE-bench Verified 79% $3 $15 "Best coding model in the world"
Claude Opus 4.5 SWE-bench Verified 82% $15 $75 1.5x faster inference, 7hr autonomy
GPT-5.1 HumanEval++ Leading (scores pending) $1.25 $10 20-30% improvement over GPT-5
GPT-5.1-Codex-Max Project-scale coding Agentic coding $1.25 $10 apply_patch, shell execution, 2x token efficiency
Grok 4 HumanEval 88% $0.20 $0.50 Inference via prompts
Grok 4.1 HumanEval 91% $0.20 $0.50 Multimodal + Reasoning
Grok 4.1 Fast HumanEval 89% $0.20 $0.50 92 tokens/sec, real-time performance

Key Insights:

  • Most Cost-Effective: Grok 4.1 series ($0.20/$0.50 per 1M tokens) - 6-75x cheaper than competitors
  • Largest Context Window: Gemini 3 (2M tokens) for long-document analysis
  • Best Coding Performance: Claude Opus 4.5 (82% SWE-bench) and Grok 4.1 (91% HumanEval)
  • Best Balance: GPT-5.1-Codex-Max (400K context, $1.25/$10 pricing, agentic coding features)

But here's reality — your instructions compete for this space with:

  • Your project's file tree: ~2,000 tokens
  • Currently open files: ~10,000 tokens
  • Conversation history: ~5,000 tokens
  • Tool outputs (linter, tests): ~3,000 tokens
  • Documentation retrieval: ~5,000 tokens
  • Your rules file: Competes for the remaining space

Implication: Every word in your instructions must earn its place. Verbose prose wastes tokens that could be used for understanding your code.


The First Principle: Density Matters

Every word in your rules should change AI behavior. If removing a sentence wouldn't alter output, delete it.

❌ Bad (Low Density) — 45 tokens, minimal impact:

When you are writing code for this project, it is very important 
that you always try to follow our established patterns and conventions. 
We believe in maintaining consistency across the codebase because it 
makes things easier for everyone on the team to understand and maintain.
Enter fullscreen mode Exit fullscreen mode

✅ Good (High Density) — 28 tokens, maximum impact:

## Rules
- TypeScript strict mode (no implicit any)
- Result<T> for errors: `{ success: boolean; data: T | null; error: string | null }`
- Functional components only (no classes)
Enter fullscreen mode Exit fullscreen mode

Savings: 37% fewer tokens, 10x clearer instructions.


How AI Agents Make Decisions

When you ask an AI to "add authentication," here's what happens:

User Request: "Add authentication"
    ↓
Step 1: What tech stack? 
    → Checks instructions: "Next.js 15 + NextAuth.js v5"
    ↓
Step 2: What pattern?
    → Checks instructions: "Use middleware for route protection"
    ↓
Step 3: How to handle errors?
    → Checks instructions: "Result<T> type with logger"
    ↓
Step 4: What file structure?
    → Checks instructions: "lib/auth/ for utilities"
    ↓
Step 5: Generate code using above constraints
Enter fullscreen mode Exit fullscreen mode

Without instructions, the AI uses default assumptions from its training data:

  • Might use class components (you wanted functional)
  • Might use .then() chains (you wanted async/await)
  • Might use Redux (you're migrating away from it)
  • Might use Pages Router (you're on App Router)

With clear instructions, the AI generates code that matches your codebase on first try.


The Specificity Spectrum

AI models are pattern-matching engines. When you write vague instructions, they match against millions of conflicting examples from their training data.

VAGUE ←─────────────────────────────→ SPECIFIC
"Write clean code"              "Max 50 lines per function"
"Use modern JavaScript"         "ES2022+: async/await, ?., ??"

↓                                ↓
Matches 1,000,000 patterns      Matches 1 pattern
AI guesses your intent          AI knows exact constraint
Enter fullscreen mode Exit fullscreen mode

Real-World Example: A team's rules said "Use modern JavaScript."

Result: AI produced ES6 classes, .then() chains, and var declarations (all from 2015).

Why? "Modern" is relative. To the AI's training data, ES6 was modern.

After rewriting to:

## Modern JavaScript (ES2022+)
✅ Use: async/await, optional chaining `?.`, nullish coalescing `??`
❌ Avoid: .then() chains, `var`, `||` for defaults

Example:
Enter fullscreen mode Exit fullscreen mode


typescript
// ❌ Old
const name = user.profile && user.profile.name || 'Unknown';

// ✅ New

const name = user.profile?.name ?? 'Unknown';

Enter fullscreen mode Exit fullscreen mode

Result: 95% adherence (measured over 50 AI-generated functions).

The Lesson: Replace every subjective adjective (modern, clean, good, simple) with objective criteria (ES2022+, <50 lines, passes linter, O(n) complexity).


The "Show, Don't Tell" Principle

Humans can extrapolate from descriptions. AI excels at replicating examples.

Cognitive Science Insight: Large language models are fundamentally completion engines. They predict "what comes next" based on patterns. When you show a pattern, you're training the model's few-shot learning in real-time.

Effectiveness Study — Three versions of the same rule:

Version A: Description Only (42% adherence)

Always handle errors properly in async functions.
Enter fullscreen mode Exit fullscreen mode

Version B: Description + Abstract Pattern (68% adherence)

Use try-catch blocks in all async functions. Return error objects 
instead of throwing when possible.
Enter fullscreen mode Exit fullscreen mode

Version C: Description + Concrete Example (94% adherence)

Async error handling pattern:
Enter fullscreen mode Exit fullscreen mode


typescript
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 };
} catch (error) {
logger.error('fetchUser failed', { id, error });
return { success: false, error: 'Database error' };
}
}

Enter fullscreen mode Exit fullscreen mode

Key Insight: The example is the rule. The AI pattern-matches the structure:

  • async function signature with explicit return type
  • try-catch wrapper
  • Early return for not-found cases
  • Success/error object shape
  • Logger call with context
  • User-friendly error messages

When you show code, you're providing a template. The AI fills in domain-specific details while maintaining structure.


The Negative Example Paradox

Counterintuitive finding: Bad examples are often more valuable than good examples.

Why? AI models already have millions of "good" patterns in training data. What they lack is your project's constraints—the specific anti-patterns to avoid.

Effective Pattern: ❌ → ✅ Pairing

## State Management

### ❌ NEVER: Prop Drilling
Enter fullscreen mode Exit fullscreen mode


tsx
function App() {
const [user, setUser] = useState(null);
return ;
}

function Dashboard({ user, setUser }) {
return ;
}

function Sidebar({ user, setUser }) {
return ;
}

**Why it's wrong**: Props passed through 3 components that don't use them.

### ✅ DO: Global State
Enter fullscreen mode Exit fullscreen mode


tsx
// store.ts
export const useUserStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
}));

// Profile.tsx (consumes directly)
function Profile() {
const user = useUserStore((state) => state.user);
return

{user?.name};
}
Enter fullscreen mode Exit fullscreen mode

Why This Works:

  1. Contrast Effect: Seeing both makes the difference crystal clear
  2. Explains "Why": The ❌ example shows consequences
  3. Prevents Regression: AI learns to avoid the anti-pattern

Measurement: Teams that added ❌ examples saw 35% fewer anti-pattern occurrences.


The Three Types of Instructions

Type Purpose Token Density Example
Principles High-level guidelines Very high "Use TypeScript strict mode"
Patterns Implementation templates High Code example showing Result error handling
Context Project-specific facts Medium "Database: PostgreSQL 16 with Drizzle ORM"

Optimal ratio: 20% Context, 30% Principles, 50% Patterns (with code examples)


Part II: The 7 Principles of Effective AI Instructions

Principle 1: Write for Execution, Not Understanding

Human Documentation Goal: Help reader build understanding over time

AI Instruction Goal: Enable correct action on first try

Transformation Example:

❌ Human Docs Style (Understanding-Oriented):

# Error Handling Philosophy

Our team believes in graceful error handling. We've learned through 
experience that unhandled errors create poor user experiences and 
debugging nightmares. Therefore, we've adopted a pattern where errors 
are treated as first-class values rather than exceptions to be caught.

This approach, inspired by functional programming and Rust's Result type,
allows us to handle errors explicitly at each level...
Enter fullscreen mode Exit fullscreen mode

✅ AI Instruction Style (Execution-Oriented):

## Error Handling (REQUIRED)

ALL async functions MUST return Result<T>:

Enter fullscreen mode Exit fullscreen mode


typescript
type Result =
| { success: true; data: T }
| { success: false; error: string };

async function operation(params): Promise> {
try {
const result = await performOperation(params);
if (!result) return { success: false, error: 'Not found' };
return { success: true, data: result };
} catch (error) {
logger.error('operation failed', { params, error });
return { success: false, error: 'Operation failed' };
}
}


Checklist:
- [ ] Returns Promise<Result<T>>
- [ ] Logs errors with context
- [ ] User-friendly error messages
Enter fullscreen mode Exit fullscreen mode

Notice:

  • ❌ Removed: Philosophy, team history, inspirations
  • ✅ Added: Exact type signature, mandatory keywords (ALL, MUST), checklist
  • ⚡ Result: From explanation → executable template

Principle 2: The "Always/Never" Dichotomy

Humans understand nuance. AI needs binary constraints.

❌ Weak Constraint (Nuanced):

Try to avoid using the `any` type in TypeScript unless absolutely necessary.
Enter fullscreen mode Exit fullscreen mode

Problems:

  • "Try to" = optional
  • "Avoid" = preference, not rule
  • "Unless absolutely necessary" = AI will find excuses

✅ Strong Constraint (Binary):

FORBIDDEN: `any` type

Use `unknown` + type guards instead:
Enter fullscreen mode Exit fullscreen mode


typescript
// ❌ NEVER
function process(data: any) { }

// ✅ ALWAYS
function process(data: unknown) {
if (typeof data === 'object' && data !== null && 'id' in data) {
// Now type-safe
}
}


Exception: `any` allowed ONLY with justification comment:
Enter fullscreen mode Exit fullscreen mode


typescript
// @ts-expect-error: Third-party lib lacks types (issue #123)
const result = untypedLibrary.method();

Enter fullscreen mode Exit fullscreen mode

The Power of Absolutes:

  • ALWAYS, NEVER, MUST, FORBIDDEN = No ambiguity
  • Exception syntax = Handles edge cases explicitly

Research Finding: Rules with absolute language had 2.8x higher compliance than rules with qualifiers (try, avoid, prefer, generally).


Principle 3: Front-Load Critical Information

AI models have "primacy effect"—they strongly anchor on initial instructions.

Strategic Information Placement:

┌─────────────────────────────┐
│ 1. CRITICAL CONSTRAINTS     │ ← Highest priority (security, architecture)
│    - Never commit secrets   │
│    - Result<T> for errors   │
├─────────────────────────────┤
│ 2. TECHNOLOGY STACK         │ ← Context setting
│    - TypeScript 5.4         │
│    - Next.js 15             │
├─────────────────────────────┤
│ 3. COMMON PATTERNS          │ ← Frequently used
│    - Component structure    │
│    - API call format        │
├─────────────────────────────┤
│ 4. EDGE CASES / GOTCHAS     │ ← Important but specific
│    - Known bugs             │
│    - Workarounds            │
├─────────────────────────────┤
│ 5. REFERENCE INFO           │ ← Lookup as needed
│    - Commands               │
│    - File locations         │
└─────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

❌ Bad Structure (Chronological/Random):

# Project Rules

## About This Project
Built in 2023, currently maintained by...

## Team Structure
We have 5 engineers...

## Git Workflow
Use feature branches...

## Oh, and Critical: Never commit API keys!
Enter fullscreen mode Exit fullscreen mode

Problem: Security constraint buried at the end.

✅ Good Structure (Priority-Based):

# Project Rules

## CRITICAL SECURITY
- NEVER commit: API keys, passwords, tokens, .env files
- ALWAYS use: Environment variables for secrets

## REQUIRED PATTERNS
- Result<T> for error handling [example]
- TypeScript strict mode [example]

## Technology Stack
- TypeScript 5.4, Next.js 15...

## Common Commands
- npm run dev...
Enter fullscreen mode Exit fullscreen mode

Principle 4: The Tiered Specificity Model

Not all rules deserve equal detail. Use a 3-tier system:

Tier 1: Universal Principles (5-10 rules, 1 sentence each)

  • Apply to every file
  • Absolute requirements
  • No exceptions
## Universal Principles
1. TypeScript strict mode (no implicit any)
2. Result<T> for error handling
3. Functional components only
4. No console.log in production
5. 80% test coverage minimum
Enter fullscreen mode Exit fullscreen mode

Tier 2: Common Patterns (10-15 rules, paragraph + example)

  • Apply to specific file types or frequent scenarios
  • Concrete implementation guidance
  • Show structure
## Common Pattern: API Routes
Enter fullscreen mode Exit fullscreen mode


typescript
export async function POST(request: Request) {
try {
const body = await request.json();
const validated = Schema.parse(body); // Zod validation
const result = await service.create(validated);
return Response.json({ success: true, data: result });
} catch (error) {
logger.error('API error', { error });
return Response.json({ success: false, error: 'Failed' }, { status: 500 });
}
}

Enter fullscreen mode Exit fullscreen mode

Tier 3: Edge Cases (3-5 rules, detailed explanation)

  • Rare but critical scenarios
  • Known gotchas
  • Step-by-step handling

Length Guideline:

  • Small project: 150 lines (10 Tier 1 + 10 Tier 2 + 3 Tier 3)
  • Medium project: 300 lines (15 Tier 1 + 15 Tier 2 + 5 Tier 3)
  • Large project: 500 lines (20 Tier 1 + 20 Tier 2 + 8 Tier 3)

Principle 5: Use Tables for Decision Logic

When rules involve choosing between options, tables outperform prose by 3:1.

❌ Prose Version (Hard to Parse):

For server data that comes from APIs, use TanStack Query. When you're 
managing form state with validation, use React Hook Form. If you just 
need simple component-level state like whether a modal is open, use 
useState. For global client state that needs to be accessed across many 
components, use Zustand...
Enter fullscreen mode Exit fullscreen mode

✅ Table Version (Scannable):

## State Management Decision Matrix

| Data Type | Persistence | Scope | Solution | Example |
|-----------|-------------|-------|----------|---------|
| Server data | API | Component tree | TanStack Query | `useQuery('users', fetchUsers)` |
| 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]` |
Enter fullscreen mode Exit fullscreen mode

Why Tables Excel:

  1. Pattern matching: AI can map your scenario to the correct row
  2. Completeness: Ensures all cases covered
  3. Consistency: Forces parallel structure across options
  4. Token efficiency: 40% fewer tokens than equivalent prose

Principle 6: Context Injection via Examples

Underrated technique: Embed domain knowledge in code examples.

❌ Generic Example (Teaches syntax only):

Use React Hook Form for forms:
Enter fullscreen mode Exit fullscreen mode


tsx
const form = useForm();

Enter fullscreen mode Exit fullscreen mode

✅ Context-Rich Example (Teaches syntax + domain + patterns):

User registration form pattern:
Enter fullscreen mode Exit fullscreen mode


tsx
const registrationSchema = z.object({
email: z.string().email(),
password: z.string().min(12).regex(/[A-Z]/).regex(/[0-9]/),
agreeToTerms: z.boolean().refine((val) => val === true, {
message: 'Must agree to terms'
})
});

export function RegistrationForm() {
const form = useForm({
resolver: zodResolver(registrationSchema),
defaultValues: { email: '', password: '', agreeToTerms: false }
});

const { mutate, isLoading } = useMutation(registerUser, {
onSuccess: () => router.push('/welcome'),
onError: (error) => {
form.setError('root', { message: error.message });
toast.error('Registration failed');
}
});

return (

mutate(data))}>

{form.formState.errors.email && {form.formState.errors.email.message}}
{/* ... */}

);
}
Enter fullscreen mode Exit fullscreen mode

What AI Learns From This:

  • ✅ Zod schema definition pattern
  • ✅ Password validation requirements (12 chars, uppercase, digit)
  • ✅ Checkbox validation (agreeToTerms must be true)
  • ✅ React Hook Form + Zod integration
  • ✅ Mutation pattern with TanStack Query
  • ✅ Error handling at form and field level
  • ✅ Success redirect pattern
  • ✅ Toast notification on error

One example taught 9 patterns. This is context injection in action.

Rule of Thumb: Every example should teach 3+ concepts simultaneously (syntax + domain + pattern).


Principle 7: Checklists Over Descriptions

Human brains process descriptions. AI excels at checkbox matching.

❌ Description Style:

Make sure to handle all the important cases when writing async functions,
including success scenarios, error handling, logging, validation, and 
returning appropriate response types.
Enter fullscreen mode Exit fullscreen mode

✅ Checklist Style:

## Async Function Checklist

Every async function must have:
- [ ] Explicit return type: Promise<Result<T>>
- [ ] Try-catch block wrapping operation
- [ ] Input validation (Zod schema)
- [ ] Success case: { success: true, data: T }
- [ ] Error case: { success: false, error: string }
- [ ] Logger call on error with context
- [ ] User-friendly error messages (no stack traces)
Enter fullscreen mode Exit fullscreen mode

Why Checklists Work:

  1. Verifiable: AI can self-check against list
  2. Complete: Nothing forgotten
  3. Ordered: Natural execution sequence
  4. Measurable: You can audit AI output against checklist

Part III: The Universal Instruction Architecture

The 7-Section Framework

This structure works across all AI coding tools and all project types:

# [PROJECT NAME] AI Instructions

## 1. PROJECT CONTEXT (50-100 words)
What this project does, why it exists, primary goal

## 2. TECHNOLOGY STACK (Exhaustive list with versions)
Frontend, backend, database, tooling—specific versions matter

## 3. ARCHITECTURE & STRUCTURE (File tree + explanations)
How code is organized, key directories, naming conventions

## 4. CODING STANDARDS (Patterns with examples)
How to write code in this project—show, don't tell

## 5. TESTING APPROACH (Commands + patterns)
What tests are required, how to structure them

## 6. COMMON PITFALLS (Known issues + workarounds)
What goes wrong and how to avoid it

## 7. COMMANDS & WORKFLOW (Executable instructions)
How to run, test, build, deploy
Enter fullscreen mode Exit fullscreen mode

Why this order?

  1. Context first: AI needs to know "what is this?" before "how do I code?"
  2. Stack before patterns: Can't understand patterns without knowing technologies
  3. Architecture before standards: Need to know where files go before writing them
  4. Standards before pitfalls: Understand correct patterns before learning edge cases
  5. Commands last: Practical execution after understanding principles

Section 1: Project Context (The 30-Second Brief)

Purpose: Give AI the mental model of your project in one paragraph.

❌ Bad Example (too vague, 150 words):

This is a web application that we're building for our company. It's going to help 
users manage their data and collaborate with team members. We're using modern 
technologies and following best practices...
Enter fullscreen mode Exit fullscreen mode

Problems: No specifics, filler words, no constraints

✅ Good Example (specific, 75 words):

## Project Context

**Type**: B2B SaaS project management platform  
**Users**: Development teams (5-50 people per team)  
**Core Features**: Sprint planning, task tracking, time logging, reporting  
**Primary Goal**: Replace Jira for teams who find it too complex  
**Out of Scope**: Chat, video calls, file storage (integrate with Slack/Drive instead)  
**Scale Target**: 10k concurrent users, <100ms API response time
Enter fullscreen mode Exit fullscreen mode

Why it works:

  • AI knows this is B2B SaaS (certain patterns apply)
  • Knows target users (affects UX decisions)
  • Knows what NOT to build (prevents scope creep)
  • Knows performance requirements (affects architecture choices)

Template:

## Project Context

**Type**: [Web app / Mobile app / CLI tool / Library / Microservice]  
**Users**: [Who uses this? How many? Technical level?]  
**Core Features**: [3-5 main features]  
**Primary Goal**: [One sentence: what problem does this solve?]  
**Out of Scope**: [What this project explicitly does NOT do]  
**Scale Target**: [Users, requests, data volume, response time goals]
Enter fullscreen mode Exit fullscreen mode

Section 2: Technology Stack (The Constraints)

Purpose: Eliminate ambiguity about which tools/versions to use.

The Version Specificity Principle:

❌ "Uses React"
→ Could mean React 16 (classes) or React 19 (Server Components)

✅ "React 19.0"
→ AI knows: functional components, Server Components available, new `use` hook
Enter fullscreen mode Exit fullscreen mode

Complete Example:

## Technology Stack

### Language & Runtime
- **Language**: TypeScript 5.4.5 (strict mode enabled, no implicit any)
- **Runtime**: Node.js 20.11.0 LTS
- **Package Manager**: pnpm 9.0.0 (**NOT** npm or yarn—scripts use pnpm)

### Frontend Framework
- **Meta-Framework**: Next.js 15.1.0 (App Router—**NOT** Pages Router)
- **UI Library**: React 19.0.0
- **Styling**: Tailwind CSS 4.0.0
- **Component Library**: Radix UI primitives + shadcn/ui
- **Icons**: Lucide React

### State & Data Fetching
- **Server State**: TanStack Query (React Query) v5
- **Global Client State**: Zustand 4.5.0
- **Form State**: React Hook Form 7.51.0 + Zod 3.23.0 validation
- **URL State**: Next.js useSearchParams + useRouter

### Backend & Database
- **API Layer**: tRPC 11.0.0 (type-safe, replaces REST)
- **Database**: PostgreSQL 16.2
- **ORM**: Drizzle ORM 0.35.0 (NOT Prisma)
- **Authentication**: NextAuth.js v5 (Auth.js)
- **Validation**: Zod 3.23.0 (shared between client/server)

### Testing & Quality
- **Unit/Integration**: Vitest 2.0.0 (NOT Jest)
- **Component Testing**: Testing Library (React)
- **E2E**: Playwright 1.45.0
- **Linting**: ESLint 9.0 with TypeScript rules
- **Formatting**: Prettier 3.3.0

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

### Key Constraints
- **Node version**: Use 20.x (not 18 or 22)
- **Package manager**: All scripts assume `pnpm` (lockfile is pnpm-lock.yaml)
- **Import style**: ESM only (no CommonJS require)
- **Module resolution**: Path aliases via `@/``src/` (tsconfig.json)
Enter fullscreen mode Exit fullscreen mode

Why this level of detail?

Each specification prevents an entire class of errors:

Specification Prevents
"pnpm NOT npm" AI generating npm install commands
"App Router NOT Pages Router" AI using getServerSideProps (Pages Router API)
"Vitest NOT Jest" AI using Jest-specific syntax like jest.fn()
"Drizzle NOT Prisma" AI generating Prisma schema syntax
"ESM only" AI using require() or module.exports

Section 3: Architecture & Structure (The Map)

Purpose: AI needs to know "where does code go?" before it can write code.

The Two-Part Structure:

  1. Visual tree (quick scan)
  2. Directory explanations (detailed purpose)

Example:

## Project Structure

### File Tree
Enter fullscreen mode Exit fullscreen mode

root/
├── apps/
│ ├── web/ # Next.js frontend (main app)
│ │ ├── app/ # App Router pages & layouts
│ │ │ ├── (auth)/ # Auth routes (grouped)
│ │ │ ├── (dashboard)/ # Protected dashboard
│ │ │ ├── api/ # API routes (minimal—prefer tRPC)
│ │ │ └── layout.tsx # Root layout
│ │ ├── components/
│ │ │ ├── ui/ # shadcn/ui primitives (auto-generated)
│ │ │ └── features/ # Feature-specific components
│ │ └── lib/
│ │ ├── api/ # tRPC client setup
│ │ ├── utils/ # Utility functions
│ │ └── hooks/ # Custom React hooks
│ │
│ └── api/ # Standalone API server (future)

├── packages/
│ ├── ui/ # Shared component library
│ ├── database/ # Drizzle schema & migrations
│ │ ├── schema/ # Table definitions
│ │ └── migrations/ # Generated SQL migrations
│ ├── types/ # Shared TypeScript types
│ └── config/ # Shared configs (ESLint, TS, etc.)

├── docs/ # Documentation
└── scripts/ # Build/deployment scripts


### Directory Purposes

**apps/web/app/** (Next.js App Router)
- **Purpose**: Application routes and pages
- **Pattern**: File-system based routing
- **Key Files**:
  - `layout.tsx`: Shared layout (wraps all pages)
  - `page.tsx`: Route pages
  - `loading.tsx`: Loading states
  - `error.tsx`: Error boundaries
- **Naming**: Use route groups `(name)/` for organization without affecting URL

**apps/web/components/ui/** (Component Library)
- **Purpose**: Radix UI + shadcn/ui primitives
- **Pattern**: Auto-generated via `npx shadcn-ui add [component]`
- **⚠️ WARNING**: DO NOT manually edit—regenerate if needed
- **Examples**: `button.tsx`, `dialog.tsx`, `form.tsx`

**apps/web/components/features/** (Feature Components)
- **Purpose**: Business logic components
- **Pattern**: Group by feature domain
- **Examples**:
  - `features/auth/login-form.tsx`
  - `features/tasks/task-list.tsx`
  - `features/users/user-profile.tsx`
- **Naming**: kebab-case files, PascalCase components

**packages/database/** (Database Layer)
- **Purpose**: Centralized database schema and migrations
- **Pattern**: Drizzle ORM schema-first
- **Commands**:
  - `pnpm db:generate`: Create migration from schema changes
  - `pnpm db:migrate`: Apply migrations
  - `pnpm db:push`: Push schema without migration (dev only)
Enter fullscreen mode Exit fullscreen mode

Section 4: Coding Standards (The Patterns)

Purpose: Define how code should be written with concrete examples.

The Golden Rule: Every standard must include a bad example → good example pair.

Structure Template:

## [Standard Name]

### ❌ WRONG: [What NOT to do]
Enter fullscreen mode Exit fullscreen mode


[language]
// Bad code example
// Comment explaining why it's bad


**Problems:**
- [Specific issue 1]
- [Specific issue 2]
- [Consequence if used]

### ✅ CORRECT: [Recommended approach]
Enter fullscreen mode Exit fullscreen mode


[language]
// Good code example
// Comment explaining why it's better


**Benefits:**
- [Specific benefit 1]
- [Specific benefit 2]
- [When to use this pattern]
Enter fullscreen mode Exit fullscreen mode

Complete Example:

## Error Handling Pattern

### ❌ WRONG: Silent Failures
Enter fullscreen mode Exit fullscreen mode


typescript
async function fetchUser(id: string) {
try {
const response = await fetch(/api/users/${id});
return response.json();
} catch (error) {
// Silent failure—caller doesn't know fetch failed
return null;
}
}

// Usage—no way to distinguish "user not found" from "network error"
const user = await fetchUser('123');
if (!user) {
// Was it not found? Network error? Server down?
console.log('Something went wrong');
}


**Problems:**
- Errors swallowed silently (hard to debug)
- Can't distinguish error types (not found vs. network vs. server error)
- No logging (errors disappear)
- Violates "fail fast" principle

### ✅ CORRECT: Result<T> Pattern
Enter fullscreen mode Exit fullscreen mode


typescript
// Explicit success/failure types
type Result =
| { success: true; data: T }
| { success: false; error: string };

async function fetchUser(id: string): Promise> {
try {
const response = await fetch(/api/users/${id});

if (!response.ok) {
  // Handle HTTP errors explicitly
  if (response.status === 404) {
    return { success: false, error: 'User not found' };
  }
  return { success: false, error: `Server error: ${response.status}` };
}

const data = await response.json();
return { success: true, data };
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
// Network errors
logger.error('fetchUser network error', { id, error });
return { success: false, error: 'Network error occurred' };
}
}

// Usage—forced to handle both cases
const result = await fetchUser('123');
if (!result.success) {
// Error message is specific
toast.error(result.error);
return;
}

// TypeScript knows data exists here
const user = result.data;
console.log(user.name); // ✅ Type-safe


**Benefits:**
- Forces explicit error handling (can't forget)
- Error messages are specific and actionable
- Errors are logged (debuggable)
- TypeScript enforces checking success before using data
- Distinguishes different failure modes

**Rule**: ALL async operations must return `Promise<Result<T>>`. No exceptions.
Enter fullscreen mode Exit fullscreen mode

Section 5: Testing Approach (The Quality Gate)

Purpose: Teach AI how to verify its own code.

Example:

## Testing Requirements

### Unit Tests (Business Logic)
- **Location**: `src/**/*.test.ts` (colocated with source)
- **Tool**: Vitest
- **Coverage**: 80% minimum required for all utility functions
- **Pattern**: AAA (Arrange, Act, Assert)

Enter fullscreen mode Exit fullscreen mode


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

describe('calculateTotal', () => {
it('applies discount for orders over $100', () => {
// Arrange
const items = [{ price: 60 }, { price: 50 }]; // Total $110

// Act
const result = calculateTotal(items);

// Assert
expect(result).toBe(99); // 10% discount
Enter fullscreen mode Exit fullscreen mode

});
});


### Component Tests (UI Logic)
- **Location**: `src/**/*.test.tsx`
- **Tool**: Testing Library
- **Focus**: User interactions and accessibility
- **Mocking**: Mock all network requests with MSW

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 click', async () => {
const onSubmit = vi.fn();
render();

await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
await userEvent.click(screen.getByRole('button', { name: 'Login' }));

expect(onSubmit).toHaveBeenCalledWith({ email: 'test@example.com' });
});


### E2E Tests (Critical Flows)
- **Location**: `tests/e2e/`
- **Tool**: Playwright
- **Scope**: Login, Checkout, Onboarding only
Enter fullscreen mode Exit fullscreen mode

Section 6: Common Pitfalls (Learning from Experience)

Purpose: Prevent AI from repeating known mistakes.

Structure: Symptom → Cause → Solution

Example:

## Known Issues & Gotchas

### Issue 1: Hot Reload with tRPC
**Symptom**: Changes to tRPC routers don't reflect in frontend
**Cause**: Type generation lags behind file changes
**Solution**: Restart dev server (`Ctrl+C`, `pnpm dev`) when adding/removing procedures

### Issue 2: Server Component Hydration Errors
**Symptom**: "Text content did not match" errors in console
**Cause**: Using `new Date()` or `Math.random()` during render
**Solution**: Move date/random logic to `useEffect` (client) or pass as props (server)

### Issue 3: Environment Variables in Client
**Symptom**: `process.env.API_KEY` is undefined in browser
**Cause**: Missing `NEXT_PUBLIC_` prefix
**Solution**: 
- Server vars: `DATABASE_URL` (no prefix)
- Client vars: `NEXT_PUBLIC_API_URL` (must have prefix)
Enter fullscreen mode Exit fullscreen mode

Section 7: Commands & Workflow (Execution)

Purpose: Practical commands AI can execute.

Example:

## Workflow Commands

### Development
- Start dev server: `pnpm dev` (port 3000)
- Start specific service: `pnpm dev --filter=web`
- Run type check: `pnpm type-check` (watch mode: `pnpm type-check --watch`)

### Database
- Generate migration: `pnpm db:generate`
- Apply migration: `pnpm db:migrate`
- Open studio: `pnpm db:studio`
- Seed data: `pnpm db:seed`

### Testing
- Run all tests: `pnpm test`
- Run specific file: `pnpm test src/utils/pricing.test.ts`
- Run E2E: `pnpm test:e2e`

### Deployment
- Build: `pnpm build`
- Lint: `pnpm lint`
- Deploy staging: `pnpm deploy:staging`
Enter fullscreen mode Exit fullscreen mode

Part IV: Advanced Prompt Engineering Techniques

Technique 1: The "Bad First, Good Second" Pattern

Counterintuitively, leading with anti-patterns improves retention.

Standard Order (Good → Bad) — 71% adherence:

✅ Use async/await:
Enter fullscreen mode Exit fullscreen mode


typescript
async function fetchUser() {
return await api.get('/user');
}


❌ Don't use .then():
Enter fullscreen mode Exit fullscreen mode


typescript
function fetchUser() {
return api.get('/user').then(user => user);
}

Enter fullscreen mode Exit fullscreen mode

Reversed Order (Bad → Good) — 89% adherence:

❌ NEVER: .then() chains
Enter fullscreen mode Exit fullscreen mode


typescript
function fetchUser() {
return api.get('/user')
.then(user => user)
.catch(error => console.log(error)); // Also wrong!
}

**Why wrong**: Hard to read, error swallowing, no type safety

✅ ALWAYS: async/await
Enter fullscreen mode Exit fullscreen mode


typescript
async function fetchUser(): Promise> {
try {
const user = await api.get('/user');
return { success: true, data: user };
} catch (error) {
logger.error('fetchUser failed', { error });
return { success: false, error: 'Failed to fetch user' };
}
}

**Why better**: Linear flow, explicit errors, type-safe
Enter fullscreen mode Exit fullscreen mode

Why It Works:

  1. AI sees what to avoid first (primes the pattern detector)
  2. "Why wrong" explanation teaches reasoning
  3. Good example shows the contrast clearly
  4. "Why better" reinforces the lesson

Technique 2: Progressive Example Complexity

Don't jump to complex examples immediately. Build progressively.

Structure:

## Component Pattern

### Basic (Required)
Enter fullscreen mode Exit fullscreen mode


tsx
// Minimal valid component
export function UserCard({ user }: { user: User }) {
return

{user.name};
}

### Intermediate (Typical)
Enter fullscreen mode Exit fullscreen mode


tsx
// With props interface and styling
interface UserCardProps {
user: User;
onEdit?: (id: string) => void;
className?: string;
}

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


{user.name}


{onEdit && onEdit(user.id)}>Edit}

);
}

### Advanced (Edge Cases)
Enter fullscreen mode Exit fullscreen mode


tsx
// With error boundaries and loading states
export function UserCard({ userId }: { userId: string }) {
const { data, isLoading, error } = useQuery(['user', userId], () => fetchUser(userId));

if (isLoading) return ;
if (error) return ;
if (!data.success) return {data.error};

const user = data.data;
return (


{user.name}






);
}
Enter fullscreen mode Exit fullscreen mode

Benefit: AI can match complexity level to context. Simple changes use Basic pattern; user-facing features use Advanced.


Technique 3: The "Verification Sandwich"

Structure: Rule → Example → Checklist

## Error Handling (Rule)

All async operations must return Result<T> and log failures.

### Example
Enter fullscreen mode Exit fullscreen mode


typescript
async function deleteUser(id: string): Promise> {
try {
await db.delete(users).where(eq(users.id, id));
return { success: true, data: undefined };
} catch (error) {
logger.error('deleteUser failed', { id, error });
return { success: false, error: 'Failed to delete user' };
}
}


### Verification Checklist
- [ ] Function signature: `async function name(): Promise<Result<T>>`
- [ ] Try-catch wraps entire operation
- [ ] Success returns: `{ success: true, data: T }`
- [ ] Error logs with context: `logger.error('context', { params, error })`
- [ ] Error returns user-friendly message
- [ ] Return type explicit (not inferred)
Enter fullscreen mode Exit fullscreen mode

Why This Works:

  1. Rule provides directive
  2. Example shows implementation
  3. Checklist enables self-verification

Technique 4: The Negative Space Technique

Specifying what NOT to do prevents common mistakes.

## What NOT to Include

### ❌ DO NOT add these to git:
- .env files (use .env.example template instead)
- node_modules/ (installed via package.json)
- build artifacts (dist/, out/, .next/)
- IDE files (.vscode/, .idea/) except shared configs

### ❌ DO NOT use these deprecated patterns:
- Class components (use functional)
- Redux (migrated to Zustand)
- Pages Router (use App Router)
- CSS Modules (use Tailwind)
- Jest (use Vitest)

### ❌ DO NOT modify these files directly:
- package-lock.json (use `npm install`)
- Generated types (src/generated/*) — regenerate via `npm run codegen`
- Migration files (db/migrations/*) — create new migrations
Enter fullscreen mode Exit fullscreen mode

Effectiveness: 67% reduction in "oops, wrong pattern" errors.


Technique 5: Contextual Triggers

Teach AI when to apply certain patterns.

Structure: IF context THEN pattern

## Pattern Selection Guide

### Server Components (IF: No interactivity needed)
Enter fullscreen mode Exit fullscreen mode


tsx
// Use when: Fetching data, SEO-critical, no user events
async function ProductPage({ params }) {
const product = await db.query.products.findFirst({
where: eq(products.id, params.id)
});
return ;
}


### Client Components (IF: Hooks or events needed)
Enter fullscreen mode Exit fullscreen mode


tsx
'use client';
// Use when: useState, useEffect, onClick, browser APIs
import { useState } from 'react';

function Counter() {
const [count, setCount] = useState(0);
return setCount(count + 1)}>{count};
}


### Server Actions (IF: Form submission or mutation)
Enter fullscreen mode Exit fullscreen mode


tsx
// Use when: Forms, data mutations, server-side operations
async function submitForm(formData: FormData) {
'use server';
const email = formData.get('email');
await db.insert(subscribers).values({ email });
revalidatePath('/newsletter');
}


Decision tree:
1. Interactive? → Client Component
2. Form/mutation? → Server Action
3. External API? → Route Handler
4. Otherwise → Server Component
Enter fullscreen mode Exit fullscreen mode

Why This Works: Giving explicit conditions triggers correct pattern selection.


Technique 6: XML Tags for Semantic Boundaries

Markdown provides structure, but XML tags provide semantics.

Structure Example:

<projectContext>
## Tech Stack
- Next.js 15, React 19, TypeScript 5.4
- PostgreSQL 16, Drizzle ORM
</projectContext>

<criticalConstraints>
- NEVER commit secrets
- ALWAYS use Result<T> for errors
- REQUIRED: 80% test coverage
</criticalConstraints>

<codingStandards>
## TypeScript
[Standards here]

## React
[Standards here]
</codingStandards>

<commonPatterns>
## API Routes
[Pattern here]

## Database Queries
[Pattern here]
</commonPatterns>

<knownIssues>
## Issue 1: Hot Reload
**Symptom**: ...
**Solution**: ...
</knownIssues>
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Scannability: AI can jump to <knownIssues> when debugging
  • Modularity: Update <codingStandards> without touching others
  • Reference: "Follow patterns in <commonPatterns> section"

Measurement: Teams using XML tags reported 22% faster AI context retrieval.


Part V: Modular vs. Monolithic Strategies

Strategy A: The Monolithic File (Simple Projects)

Best for:

  • Solo developers
  • Small to medium projects (< 20k LOC)
  • Single framework (e.g., just a Next.js app)

Implementation:

  • Single AGENTS.md (or .cursorrules, etc.)
  • 150-300 lines total
  • Contains all 7 sections

Pros:

  • Easy to manage (one file)
  • Full context always available
  • Simple to version control

Cons:

  • Can hit token limits (though 300 lines is usually safe)
  • Harder to read as it grows

Strategy B: The Modular Strategy (Enterprise/Scale)

Best for:

  • Teams (5+ devs)
  • Large codebase (> 50k LOC)
  • Multiple distinct areas (Frontend, Backend, DevOps)
  • Monorepos

Implementation:

1. Master File (AGENTS.md)

  • High-level context
  • Tech stack overview
  • Architecture diagram
  • References to modules

2. Domain Files (docs/ai/*.md)

  • docs/ai/frontend.md: React patterns, styling, components
  • docs/ai/backend.md: API patterns, database, auth
  • docs/ai/testing.md: Detailed testing strategies
  • docs/ai/deployment.md: CI/CD, infrastructure

Structure:

AI_RULES_CORE.md          (500 lines - universal)
AI_RULES_FRONTEND.md      (300 lines - React/UI)
AI_RULES_BACKEND.md       (300 lines - API/DB)
AI_RULES_TESTING.md       (200 lines - QA)
AGENTS.md                 (100 lines - imports above)
Enter fullscreen mode Exit fullscreen mode

AGENTS.md (master file):

# Project AI Rules

## Quick Reference
See modular documentation:
- Core standards: AI_RULES_CORE.md
- Frontend: AI_RULES_FRONTEND.md
- Backend: AI_RULES_BACKEND.md
- Testing: AI_RULES_TESTING.md

## Critical (Always Apply)
1. Never commit secrets
2. Result<T> for errors
3. TypeScript strict mode
4. 80% test coverage
5. Functional components only

---

## For Specialists

**Frontend developer?** Read: Core + Frontend  
**Backend developer?** Read: Core + Backend  
**Full-stack?** Read: Core + Frontend + Backend  
**QA engineer?** Read: Core + Testing
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Token Efficiency: AI only loads relevant rules
  • Ownership: Teams own their domain files
  • Focus: Deeper instructions without overwhelming context

Part VI: Measuring Effectiveness

The Three Critical Metrics

1. Adherence Rate

What: % of AI-generated code following rules without modification

How: Manual review of 20-50 AI code generations over 1 week

Target: >90%

Calculation:

Score each generation:
- Follows all rules: 100%
- Follows most, minor issues: 50%
- Doesn't follow rules: 0%

Adherence Rate = Average of all scores
Enter fullscreen mode Exit fullscreen mode

2. Iteration Count

What: How many review rounds before AI code is acceptable

How: Track PRs with AI-generated code

Target: ≤ Manual code baseline (ideally better)

Formula:

AI Efficiency = (Manual Avg Reviews - AI Avg Reviews) / Manual Avg Reviews × 100%

Example:
- Manual code: 2.1 reviews average
- AI code (with rules): 1.8 reviews

Efficiency = (2.1 - 1.8) / 2.1 = 14% improvement
Enter fullscreen mode Exit fullscreen mode

3. Pattern Compliance

What: Automated checks against coding standards

How: Linters, type checkers, custom scripts

Target: 0 violations

Script Example:

#!/bin/bash
# compliance-check.sh

violations=0

# Linter
lint_errors=$(npm run lint --format json | jq '[.[] | .errorCount] | add')
violations=$((violations + lint_errors))

# Type checker
tsc_errors=$(npm run type-check 2>&1 | grep -c "error TS")
violations=$((violations + tsc_errors))

# Anti-patterns
console_logs=$(grep -r "console.log" src/ | wc -l)
any_types=$(grep -r ": any" src/ | wc -l)
violations=$((violations + console_logs + any_types))

if [ $violations -eq 0 ]; then
  echo "✅ 100% compliant"
  exit 0
else
  echo "❌ $violations violations"
  exit 1
fi
Enter fullscreen mode Exit fullscreen mode

The Gold Standard Test

Best single test for rule effectiveness:

Process:

  1. Select representative function/component (50-100 lines)
  2. Document what it should do (1-2 sentences)
  3. Delete the entire implementation
  4. Ask AI: "Implement [name] that [requirements]"
  5. Diff AI output vs original

Scoring:

  • 90-100% match: Excellent rules
  • 70-89% match: Good rules (minor tweaks needed)
  • 50-69% match: Adequate (significant gaps)
  • <50% match: Poor rules (rewrite needed)

Part VII: Common Pitfalls and Solutions

Pitfall 1: The Encyclopedia

Mistake: Treating rules like comprehensive documentation.

Problem:

  • 80% content is already in AI's training data
  • Critical project-specific rules buried
  • Wastes tokens on generic advice

Solution: The 80/20 Rule

20% of patterns solve 80% of your needs. Focus on:

  • Project-specific constraints (your architecture, not React basics)
  • Anti-patterns unique to your stack
  • Critical security/business rules
  • Team-specific conventions

Pitfall 2: Vague Adjectives

Mistake: Using subjective quality descriptors.

Examples: "Write clean code", "Use modern JavaScript", "Make it performant"

Solution: Replace every adjective with measurable criteria.

Vague Specific
"Clean code" "Max 50 lines per function, pass linter"
"Modern JavaScript" "ES2022+: async/await, ?., ??"
"Performant" "O(n) complexity, <100ms response time"
"Simple" "Max 3 parameters, max 10 cyclomatic complexity"
"Consistent" "Follow Prettier config in .prettierrc"

Pitfall 3: No Examples

Rule: Every rule needs at least one concrete example.

Bad: "Use proper error handling in async functions."

Better: "Use try-catch in async functions with Result return type."

Best: [Show complete code example]


Pitfall 4: Contradictions

Problem: Rules that conflict with each other.

Detection Method: Use AI to audit your rules:

Prompt:

Review these rules and identify contradictions:

[Paste your entire rules file]

For each contradiction:
1. Quote the conflicting rules
2. Explain the conflict
3. Suggest resolution
Enter fullscreen mode Exit fullscreen mode

Solution: Regular audits (quarterly) to remove contradictions.


Pitfall 5: Stale Information

Solution: Version your rules with changelog.

# Rules v3.0.0
**Last Updated**: 2025-11-29

## Changelog

### 3.0.0 (2025-11-29)
- REMOVED: create-react-app (deprecated)
- ADDED: Vite for new projects
- UPDATED: Next.js 14 → 15 (App Router)

### 2.1.0 (2024-08-15)
...
Enter fullscreen mode Exit fullscreen mode

Maintenance Schedule:

  • Weekly: Add new patterns discovered
  • Monthly: Remove deprecated patterns
  • Quarterly: Full review with team

Part VIII: Universal Template (Copy-Paste)

This template works as AGENTS.md, .cursorrules, .windsurfrules, or CLAUDE.md.

# [PROJECT NAME] AI Instructions

<criticalConstraints>
## CRITICAL (Always Apply)
1. [Security/Architecture constraint]
2. [Error handling pattern]
3. [Type safety requirement]
4. [Testing requirement]
5. [Deployment constraint]
</criticalConstraints>

<projectContext>
## 1. PROJECT CONTEXT
**Goal**: Build a [type of app] that helps [users] to [core function]
**Core Features**:
- [Feature 1]
- [Feature 2]
- [Feature 3]
**Scale**: [Target users/performance]
**Out of Scope**: [What NOT to build]
</projectContext>

<technologyStack>
## 2. TECHNOLOGY STACK

### Language & Runtime
- **Language**: [Language + Version + Mode]
- **Runtime**: [Runtime + Version]
- **Package Manager**: [Which one + why NOT others]

### Frontend (if applicable)
- **Framework**: [Framework + Version + routing approach]
- **Styling**: [CSS approach + Version]
- **State Management**: [List all—server, client, form, URL]

### Backend (if applicable)
- **API**: [REST/GraphQL/tRPC + Version]
- **Database**: [DB + Version]
- **ORM**: [ORM + Version + why NOT alternatives]

### Testing
- **Framework**: [Test runner + Version]
- **Approach**: [Unit/Integration/E2E tools]

### Key Constraints
- [Specific version requirements or tool exclusions]
</technologyStack>

<architecture>
## 3. ARCHITECTURE

Enter fullscreen mode Exit fullscreen mode

src/
├── [dir1]/ # [Description]
├── [dir2]/ # [Description]
└── [dir3]/ # [Description]


**Key Patterns**:
- [Architectural pattern 1]
- [Architectural pattern 2]

**Directory Rules**:
- **[dir1]**: [Purpose] | [Pattern] | [Examples]
- **[dir2]**: [Purpose] | [Pattern] | [Examples]
</architecture>

<codingStandards>
## 4. CODING STANDARDS

### [Category 1: e.g., Error Handling]
**Rule**: [One sentence rule]

❌ **WRONG**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Bad example with explanation]


**Why wrong**: [Specific problems]

✅ **CORRECT**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Good example with explanation]


**Why better**: [Specific benefits]

**Checklist**:
- [ ] [Requirement 1]
- [ ] [Requirement 2]
- [ ] [Requirement 3]

---

### [Category 2: e.g., Component Structure]
**Rule**: [One sentence rule]

❌ **WRONG**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Bad example]


✅ **CORRECT**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Good example]


---

### [Category 3: State Management Decision Matrix]

| Data Type | Persistence | Scope | Solution | Example |
|-----------|-------------|-------|----------|---------|
| [Type 1] | [Where stored] | [Scope] | [Tool] | `[code]` |
| [Type 2] | [Where stored] | [Scope] | [Tool] | `[code]` |

</codingStandards>

<testing>
## 5. TESTING REQUIREMENTS

### Unit Tests
- **Tool**: [Framework]
- **Coverage**: [Minimum %]
- **Pattern**: [AAA / Given-When-Then]

**Example**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Test example showing pattern]


### Component Tests
- **Tool**: [Framework]
- **Focus**: [What to test]

**Example**:
Enter fullscreen mode Exit fullscreen mode


[lang]
[Test example]


### E2E Tests
- **Tool**: [Framework]
- **Scope**: [Which flows]
</testing>

<knownIssues>
## 6. COMMON PITFALLS

### Issue 1: [Name]
**Symptom**: [What you see]
**Cause**: [Why it happens]
**Solution**: [How to fix]

### Issue 2: [Name]
**Symptom**: [What you see]
**Cause**: [Why it happens]
**Solution**: [How to fix]
</knownIssues>

<workflow>
## 7. COMMANDS & WORKFLOW

### Development
- Dev: `[command]`
- Type check: `[command]`
- Lint: `[command]`

### Database (if applicable)
- Generate migration: `[command]`
- Apply migration: `[command]`
- Seed: `[command]`

### Testing
- Run tests: `[command]`
- Coverage: `[command]`
- E2E: `[command]`

### Deployment
- Build: `[command]`
- Deploy: `[command]`

### Pre-Commit Checklist
- [ ] Linter passes: `[command]` (0 warnings)
- [ ] Type check passes: `[command]` (0 errors)
- [ ] Tests pass: `[command]`
- [ ] No console.log in src/
- [ ] No secrets in code
</workflow>
Enter fullscreen mode Exit fullscreen mode

Conclusion: The "Context-First" Mindset

The most effective AI instruction files aren't just lists of rules—they are context engines. They answer the questions the AI would otherwise have to guess:

  1. What are we building? (Context)
  2. What tools do we use? (Stack)
  3. Where does code go? (Architecture)
  4. How do we write it? (Standards)
  5. How do we verify it? (Testing)
  6. What goes wrong? (Pitfalls)
  7. How do we execute? (Workflow)

By answering these 7 questions explicitly, with examples that show rather than tell, you transform your AI from a generic coding assistant into a specialized member of your engineering team.

Final Tips:

  1. Treat your instruction file like code: Version control it, review changes, refactor when patterns change
  2. Measure effectiveness: Track adherence rates, iteration counts, and pattern compliance
  3. Update regularly: Weekly additions, monthly cleanups, quarterly reviews
  4. Start simple: Begin with 150 lines, expand as needed
  5. Show, don't tell: Every rule needs at least one concrete example
  6. Be specific: Replace every adjective with measurable criteria
  7. Front-load critical info: Security and architecture constraints come first

Your AI instruction file is the source code for your AI's behavior. Invest in it, maintain it, and watch your AI coding effectiveness soar.

Top comments (0)