How to Configure AI Coding Agents with Project-Level Instructions
Every time you start a new session with an AI coding agent, it walks into your codebase cold. It doesn't know that you use Zustand instead of Redux, that your tests live in __tests__ directories next to source files, or that your team settled on early returns over nested conditionals after a three-week debate. Without that context, the agent guesses. Sometimes it guesses right. Often it doesn't, and you spend more time correcting its output than you saved by using it.
Project-level configuration files solve this. They're onboarding documents for AI agents: concise descriptions of your project's conventions, architecture, and constraints that get loaded automatically at the start of every session. The agent reads them, internalizes the rules, and produces code that actually fits your codebase.
This guide covers how to set up project-level instructions for the major AI coding agents — Claude Code, Cursor, Aider, and Codex — along with universal patterns that work regardless of which tool you use.
Why Project-Level Configuration Matters
Consider what happens without configuration. You ask an agent to add a new API route. It produces a perfectly functional route, but:
- It uses Express-style middleware when your project uses Hono
- It writes tests with Vitest when you use Jest
- It puts the test file in a top-level
tests/directory when your convention is co-located__tests__/folders - It adds
try/catchblocks withconsole.errorwhen your project uses a structured error handler - It imports with relative paths when you have
@/path aliases configured
Every one of these mismatches costs you time. You either fix them manually, or you include the same corrections in every prompt. Project-level config files eliminate this entire category of friction.
The math is simple: you write the config once, and it applies to every agent session for the lifetime of the project. If you run even two agent sessions a week, the time saved compounds fast.
CLAUDE.md (Claude Code)
CLAUDE.md is the configuration file for Claude Code. It's a Markdown file that Claude reads at the start of every session to understand your project. Of all the agent config formats, it's the most flexible — there's no schema or required structure, just plain Markdown that you write however makes sense for your project.
Where to Place It
Put a CLAUDE.md file in your project root. Claude Code automatically detects and reads it when you start a session in that directory.
You can also place additional CLAUDE.md files in subdirectories. Claude reads these when it's working within that directory, so you can provide more specific instructions for different parts of your codebase. For example:
my-project/
CLAUDE.md # Project-wide conventions
packages/
api/
CLAUDE.md # API-specific instructions
web/
CLAUDE.md # Frontend-specific instructions
Claude also supports a user-level configuration at ~/.claude/CLAUDE.md for personal preferences that apply across all your projects (more on layered configuration later).
What to Include
A good CLAUDE.md covers six areas:
- Project overview — What the project is, in one or two sentences
- Tech stack — Languages, frameworks, and key dependencies with versions
- Coding conventions — Naming, patterns, and style rules that aren't captured by your linter
- Project structure — Where things live and why
- Commands — How to build, test, lint, and run the project
- Guardrails — Things the agent should never do
Example CLAUDE.md
Here's a well-structured CLAUDE.md for a Next.js + TypeScript project:
# Project: Acme Analytics Dashboard
SaaS analytics dashboard for e-commerce businesses. Next.js 14 app router
with TypeScript, Tailwind CSS, and Drizzle ORM over PostgreSQL.
## Tech Stack
- Next.js 14 (app router, not pages)
- TypeScript 5.3 (strict mode)
- Tailwind CSS 3.4
- Drizzle ORM with PostgreSQL
- Vitest for unit tests, Playwright for e2e
- pnpm as package manager
## Coding Conventions
- Use named exports, not default exports
- Prefer early returns over nested conditionals
- Max function length: 30 lines. Extract helpers if longer.
- Use `type` over `interface` unless extending
- Server components by default; add "use client" only when needed
- Error handling: throw AppError from src/lib/errors.ts, never raw Error
## Project Structure
- src/app/ — Next.js app router pages and layouts
- src/components/ — Shared React components (PascalCase filenames)
- src/lib/ — Utilities and shared logic
- src/db/ — Drizzle schema, migrations, and queries
- src/actions/ — Server actions
## Commands
- `pnpm dev` — Start dev server
- `pnpm build` — Production build
- `pnpm test` — Run Vitest unit tests
- `pnpm test:e2e` — Run Playwright tests
- `pnpm lint` — ESLint + Prettier check
- `pnpm db:migrate` — Run database migrations
## Rules
- Never modify files in src/db/migrations/ — generate new migrations instead
- Never install new dependencies without asking first
- Always run `pnpm test` after making changes
- Always run `pnpm lint` and fix issues before finishing
Tips for Effective CLAUDE.md Files
Keep it concise. Claude reads this file at the start of every session. A 200-line CLAUDE.md dilutes the important information. Aim for 40-80 lines. If you need more detail for specific subsystems, use nested CLAUDE.md files in subdirectories.
Include the "why," not just the "what." Instead of "use early returns," write "use early returns over nested conditionals — keeps functions flat and readable." The reasoning helps Claude apply the principle to novel situations, not just the specific cases you listed.
Update it as your project evolves. If your team switches from Jest to Vitest, update the CLAUDE.md. Stale config is worse than no config because it produces confidently wrong output.
List actual commands. Don't assume Claude knows how to run your tests. Spell out pnpm test, pnpm lint, pnpm build explicitly. These commands get used in verification steps after code changes.
Cursor Rules (.cursorrules / .cursor/rules)
Cursor uses its own configuration format for project-level instructions. If you use the Cursor editor, this is how you tell its AI features about your project conventions.
File Location and Format
Cursor supports two locations:
.cursorrulesin your project root (legacy format, still supported).cursor/rules/directory with multiple rule files (newer format, more flexible)
The .cursor/rules/ directory lets you create multiple rule files with different scopes. Each file can specify which file patterns it applies to:
.cursor/
rules/
global.md # Applies everywhere
react.md # Applies to component files
api.md # Applies to API route files
Example .cursorrules
Here's a .cursorrules for a React + TypeScript project:
You are working on a React 18 + TypeScript application using Vite.
## Component Patterns
- Use functional components with arrow function syntax
- Props types defined with `type`, not `interface`
- Co-locate component styles using CSS modules (ComponentName.module.css)
- Destructure props in the function signature
- Use named exports: `export const Button = () => {}`
## State Management
- Use Zustand for global state (stores in src/stores/)
- Use React Query for server state (hooks in src/hooks/queries/)
- Local state with useState only for UI-specific state (open/closed, hover, etc.)
## Import Order
1. React and third-party libraries
2. Internal modules (@/ path aliases)
3. Relative imports
4. Style imports
Always use the @/ path alias for non-relative imports.
## File Organization
- Components: src/components/{ComponentName}/{ComponentName}.tsx
- Pages: src/pages/{PageName}/index.tsx
- Hooks: src/hooks/use{HookName}.ts
- Utils: src/lib/{utilName}.ts
## Testing
- Test files: src/components/{ComponentName}/{ComponentName}.test.tsx
- Use React Testing Library, not Enzyme
- Test behavior, not implementation details
- Use `screen.getByRole` over `getByTestId` when possible
How Cursor Rules Differ from CLAUDE.md
Cursor rules are optimized for editor-integrated AI features: autocomplete, inline edits, and chat within the editor. They tend to focus more on code patterns, component structure, and naming conventions — the things that matter for real-time code generation.
CLAUDE.md is designed for agentic workflows where Claude Code operates autonomously: reading multiple files, running commands, making architectural decisions. It tends to include more operational information like build commands, testing procedures, and system-level constraints.
If you use both Cursor and Claude Code on the same project, maintain both config files. There's inevitably overlap, but each serves its tool best.
Aider Configuration (.aider.conf.yml)
Aider takes a different approach to configuration. Instead of a free-form instructions file, it uses a structured YAML config for operational settings and a separate conventions mechanism for coding instructions.
Configuration File
Create .aider.conf.yml in your project root:
# Model configuration
model: claude-sonnet-4-20250514
edit-format: diff
# Auto-commit behavior
auto-commits: true
commit-prompt: "Write a concise commit message in imperative mood. No prefixes."
# Linting and testing
lint-cmd: "npm run lint"
test-cmd: "npm test"
auto-lint: true
auto-test: true
# Context management
map-tokens: 2048
subtree-only: false
The key options:
- model — Which LLM to use for code generation
- edit-format — How Aider applies changes (
diff,whole,udiff).diffis most efficient for large files. - auto-commits — Whether Aider commits changes automatically after each edit
- lint-cmd / test-cmd — Commands to run for linting and testing. When
auto-lintandauto-testare enabled, Aider runs these after every change and fixes issues automatically.
.aiderignore
The .aiderignore file works like .gitignore but for Aider's context. Use it to exclude files that are large, generated, or irrelevant:
# Generated files
dist/
build/
*.min.js
*.generated.ts
# Large data files
fixtures/
*.sql
# Sensitive files
.env*
credentials/
# Lock files (large and not useful for context)
package-lock.json
pnpm-lock.yaml
Keeping unnecessary files out of Aider's context window improves response quality and reduces token usage.
Coding Conventions for Aider
For coding style instructions (the equivalent of CLAUDE.md or .cursorrules), Aider reads a CONVENTIONS.md file if present. You can also pass conventions inline:
# In .aider.conf.yml
read: ["CONVENTIONS.md", "ARCHITECTURE.md"]
This tells Aider to read these files as context at the start of every session.
Codex Configuration
OpenAI's Codex CLI uses a codex.json or project-level instructions file for configuration. The approach is similar to CLAUDE.md — a Markdown instructions file that the agent reads at session start.
Create a codex.md (or the format specified by your Codex version) in your project root:
## Project Context
Node.js REST API using Express, TypeScript, and Prisma ORM.
## Conventions
- Controllers in src/controllers/, services in src/services/
- Use Prisma for all database access (never raw SQL)
- Validation with zod schemas in src/schemas/
- Error responses follow RFC 7807 (Problem Details)
## Commands
- npm run dev — Start development server
- npm test — Run Jest tests
- npm run lint — Run ESLint
The general pattern across all agents is the same: tell the agent about your stack, your conventions, and your commands. The file format and specific features differ, but the content is largely portable.
Universal Patterns That Work Across All Agents
Regardless of which AI coding tool you use, certain information always improves agent output. If you do nothing else, document these six things:
1. Tech Stack and Versions
## Tech Stack
- Python 3.12
- FastAPI 0.109
- SQLAlchemy 2.0 with async support
- PostgreSQL 16
- pytest for testing
- Ruff for linting
Version numbers matter. An agent that knows you're on SQLAlchemy 2.0 won't generate 1.x-style query patterns.
2. Coding Style
## Style
- Use snake_case for functions and variables
- Use PascalCase for classes and type aliases
- Max line length: 88 characters (Black default)
- Prefer composition over inheritance
- Use dataclasses for simple data containers, Pydantic models for validation
Be specific. "Write clean code" means nothing. "Use early returns, max 20 lines per function, no nested ternaries" is actionable.
3. Testing Expectations
## Testing
- Framework: pytest with pytest-asyncio
- Tests live in tests/ mirroring the src/ structure
- Use factory_boy for test data (factories in tests/factories/)
- Minimum coverage: 80% for new code
- Always test error cases, not just happy paths
4. Build and Lint Commands
## Commands
- `make dev` — Start development server with hot reload
- `make test` — Run full test suite
- `make test-fast` — Run tests without coverage
- `make lint` — Run Ruff linter
- `make format` — Auto-format with Ruff
- `make typecheck` — Run mypy
5. Files and Directories to Never Modify
## Do Not Modify
- alembic/versions/ — Never edit migrations, generate new ones with `make migration`
- src/generated/ — Auto-generated from OpenAPI spec
- .github/workflows/ — CI config managed separately
- docker-compose.prod.yml — Production config, do not touch
6. Error Handling and Dependency Rules
## Error Handling
- Use AppException subclasses from src/exceptions.py
- Never catch broad Exception — always catch specific types
- All API errors must return structured JSON responses
## Dependencies
- Do not add new dependencies without approval
- Prefer stdlib solutions over third-party packages for simple tasks
- If a new dependency is genuinely needed, mention it before installing
Advanced Patterns
Layered Configuration
Most agents support some form of layered configuration: global user-level settings, project-level settings, and directory-level settings. Use all three layers strategically.
Global (user-level): Personal preferences that apply everywhere. Your preferred code style, common constraints, and tools you always use.
# ~/.claude/CLAUDE.md (applies to all projects)
## Personal Preferences
- I prefer explicit over implicit
- Always explain non-obvious decisions in code comments
- When uncertain between two approaches, ask me rather than guessing
- Run tests after changes unless I say otherwise
Project-level: Team conventions and project-specific rules. This is what gets committed to the repository and shared with everyone.
# /project/CLAUDE.md
# (the main config as shown earlier)
Directory-level: Specific rules for subsystems. The frontend has different conventions than the API. The migration scripts have different rules than application code.
# /project/packages/api/CLAUDE.md
## API-Specific Rules
- All routes must include OpenAPI JSDoc annotations
- Use middleware for auth — never check tokens in route handlers
- Response types must be defined in src/types/responses.ts
Claude Code merges these automatically — directory-level rules supplement, not replace, project-level rules.
Task-Specific Instructions
Some teams maintain a set of prompt templates for different types of work. You can store these alongside your project config:
.claude/
CLAUDE.md
prompts/
new-feature.md
bug-fix.md
refactor.md
code-review.md
Each template includes the standard constraints plus task-specific guidance:
# .claude/prompts/bug-fix.md
When fixing a bug:
1. First, reproduce the issue by running the failing test or creating one
2. Identify the root cause — don't just fix the symptom
3. Write a test that specifically covers the bug before fixing it
4. Make the minimal change needed to fix the issue
5. Run the full test suite to check for regressions
6. Do not refactor surrounding code — fix only the bug
You can reference these in your prompts: "Follow the bug-fix workflow in .claude/prompts/bug-fix.md."
Team-Shared vs. Personal Configuration
Commit your project-level config files to version control. They're documentation about your project's conventions, and the whole team benefits from agents that follow consistent rules.
# .gitignore — do NOT ignore these
# CLAUDE.md (commit this)
# .cursorrules (commit this)
# .aider.conf.yml (commit this)
# .aiderignore (commit this)
Personal preferences that might conflict with teammates (preferred verbosity, interaction style, model choices) go in user-level config files that are not committed to the repository.
Version Controlling Your AI Config
Treat AI config files like any other project configuration. Review changes in PRs. When someone updates the CLAUDE.md to reflect a new convention, that change should be reviewed just like a linting rule change. It affects how every agent on the team behaves.
A useful pattern is to update the AI config in the same PR as the convention change it reflects. Switching from Jest to Vitest? Update the test runner, update the CI config, and update the CLAUDE.md in a single PR.
Common Mistakes
Making Config Files Too Long
A 300-line CLAUDE.md is a wall of text that dilutes important rules. Agents process the whole file, but emphasis matters. If rule 47 of 100 says "never modify migration files," it carries less weight than if it's one of ten clearly stated rules.
Keep your main config under 80 lines. If you need more detail, use subdirectory-level configs or supplementary documents that you reference selectively.
Being Too Vague
# Bad
- Write clean, maintainable code
- Follow best practices
- Use proper error handling
# Good
- Max 20 lines per function; extract helpers for longer logic
- Use early returns to avoid nesting deeper than 2 levels
- Wrap external calls in try/catch; use AppError from src/lib/errors.ts
Vague instructions leave room for the agent to interpret, and its interpretation might not match yours. Concrete rules produce consistent output.
Not Updating Config When Conventions Change
Your team switches from CSS Modules to Tailwind. The agent keeps generating CSS Module files because your config still says to use them. Stale instructions actively work against you — they're worse than no instructions at all because you trust that the agent knows your conventions.
Add "update AI config" as a checklist item in your project's convention-change process.
Including Secrets or API Keys
This should be obvious, but it happens: someone puts database connection strings or API keys in the config file because the agent "needs to know how to connect." It doesn't. The agent uses environment variables like any other part of your application.
# Never do this
Database URL: postgres://admin:secretpassword@prod-db:5432/myapp
# Do this instead
Database: PostgreSQL 16, connection via DATABASE_URL environment variable
Contradicting Yourself Across Config Files
If your CLAUDE.md says "use Vitest" and your .cursorrules says "use Jest," you'll get inconsistent results depending on which tool you're using. Keep your config files in sync, or at minimum, don't contradict yourself on fundamental choices.
Template to Get Started
Here's a minimal but effective starter template. Copy it, replace the placeholders, and delete any sections that don't apply. You can always add more detail later.
# Project: [PROJECT_NAME]
[One sentence describing what this project is.]
## Tech Stack
- [Language and version]
- [Framework and version]
- [Database]
- [Test framework]
- [Package manager]
## Coding Conventions
- [Naming convention: snake_case / camelCase / PascalCase for what]
- [Import ordering preference]
- [Function length limit]
- [Key architectural pattern: e.g., "service layer for business logic, controllers for HTTP"]
- [Error handling approach]
## Project Structure
- [src/dir1/ — description]
- [src/dir2/ — description]
- [tests/ — description]
## Commands
- `[command]` — Start dev server
- `[command]` — Run tests
- `[command]` — Lint and format
- `[command]` — Build for production
## Do Not Modify
- [List files/directories that should never be changed by the agent]
## Rules
- Always run tests after making changes
- Do not add new dependencies without asking
- [Any other hard rules specific to your project]
Filling this out takes ten minutes. It saves hours over the next month.
Agents UI lets you run multiple configured agents side by side in a single terminal window, so you can see how different configurations affect agent behavior in real time. If you're running Claude Code, Aider, or Codex across projects with different conventions, having all sessions visible at once makes it easy to verify your config files are working as expected.