Skip to content

Topic · A5

aider CONVENTIONS.md Per-Stack Templates

aider reads CONVENTIONS.md at repo root before each chat. The file is the single best lever for getting consistent output. This is the per-stack template library — Next.js, Rails, Django, Go, Rust — plus the architect/editor mode pairing for each.

aider — the terminal coding agent that pre-dates Claude Code, Cursor, and Codex CLI — reads CONVENTIONS.md at repo root before every chat. The file is the single highest-leverage configuration aider exposes. Get it right and aider produces consistent, on-stack output. Get it wrong (vague rules, missing versions, no test conventions) and aider drifts toward generic patterns.

This page is the template library — one per common stack, with the architect/editor mode pairing and the trim list (what to leave out). The templates draw from Paul Gauthier's aider docs, the patterns we've extracted from auditing production aider setups, and the broader AGENTS.md ecosystem stewarded by the Linux Foundation Agentic AI Foundation.

The shape of a good CONVENTIONS.md

Five sections, in this order:

  1. Stack and versions — what we use, what version
  2. Code style — formatter, linter, naming
  3. Architecture — how state flows, where validation lives
  4. Tests — framework, conventions, mocking policy
  5. Avoid — what NOT to do
Under 60 lines is the discipline. Under 120 lines is the practical cap. Over 300 lines is when later instructions stop landing reliably.

Template: Next.js 15 + TypeScript

# Project conventions

Stack

  • Next.js 15.0+ with App Router (NOT Pages Router)
  • React 19
  • TypeScript 5.6 (strict mode)
  • Tailwind v4
  • Drizzle ORM with Postgres
  • Vercel deployment

Code style

  • Prettier (defaults)
  • ESLint (next/core-web-vitals)
  • Imports: third-party, then aliased (@/), then relative
  • Filenames: kebab-case for routes, PascalCase for components
  • Server components by default; "use client" only when needed

Architecture

  • App Router file-system routing
  • Server Actions for mutations (no /api/ routes unless webhook)
  • Validation: Zod schemas in src/lib/schemas/, shared client+server
  • Auth: NextAuth.js v5; session via auth() helper, never useSession in server components
  • Database: Drizzle with prepared statements; never raw SQL

Tests

  • Vitest for unit tests
  • Playwright for E2E
  • Files: foo.test.ts beside foo.ts
  • Mock only third-party APIs; never mock our own modules

Avoid

  • Pages Router patterns (getServerSideProps, _app.tsx)
  • Class components
  • CSS modules (use Tailwind)
  • Default exports (named only, except Next.js page/layout/loading)
  • "any" type (use unknown and narrow)
Architect/editor pairing: Opus 4.7 architect + Sonnet 4.7 editor. The App Router patterns require strong planning (server vs client components are non-obvious); Sonnet handles the implementation well at one-fifth the cost.

Template: Ruby on Rails 8 + Hotwire

# Project conventions

Stack

  • Rails 8.0+
  • Ruby 3.3
  • Hotwire (Turbo + Stimulus), NO React/Vue
  • Tailwind v4 via tailwindcss-rails gem
  • Postgres 16

Code style

  • Standard Ruby formatter (NOT RuboCop with default rules)
  • Filenames: snake_case
  • Methods: snake_case; predicate methods end with ?
  • Classes: PascalCase

Architecture

  • Fat models, skinny controllers (Rails Way)
  • Service objects in app/services/ for cross-model operations
  • Strong Parameters everywhere
  • Turbo Streams for live updates; never polling
  • Authentication: built-in Rails 8 auth (NOT Devise unless migrating)
  • Background jobs: Solid Queue (NOT Sidekiq)

Tests

  • Minitest (Rails default)
  • Fixtures over factories
  • One test file per model/controller/job
  • System tests in test/system/ with Capybara + Cuprite

Avoid

  • ActionCable (use Turbo Streams)
  • jQuery
  • Multiple-database setups unless explicitly needed
  • Helper modules with logic (move to presenters or service objects)
  • Mocking ActiveRecord
Architect/editor pairing: Opus 4.7 alone. Rails projects are usually small enough that the architect/editor split adds latency without saving much; one strong model handles both.

Template: Django + DRF + Python

# Project conventions

Stack

  • Django 5.0+
  • Django REST Framework 3.15
  • Python 3.12
  • Postgres 16
  • Celery for background tasks
  • Redis for cache

Code style

  • Black (line length 100)
  • isort
  • mypy strict
  • type hints on every function signature

Architecture

  • DRF ViewSets for CRUD; APIView for custom endpoints
  • Serializers for input validation (NOT marshmallow)
  • Models thin; business logic in services/ module
  • Permissions: DRF permission classes; never inline checks
  • Database queries: select_related/prefetch_related on every queryset

Tests

  • pytest with pytest-django
  • factory-boy for fixtures
  • One test file per app/views.py, app/services.py
  • Use real database in tests (NOT mocked ORM)

Avoid

  • function-based views in DRF code
  • Generic CBVs without subclassing
  • Migrations from --fake (write proper migrations)
  • f-strings in SQL (use ORM or parameterized raw queries)
  • print() in production code (use structlog)
Architect/editor pairing: Sonnet 4.7 architect + Sonnet 4.7 editor. Django's conventions are stable enough that Sonnet handles planning well; no Opus needed unless touching Django internals.

Template: Go services + sqlc + chi

# Project conventions

Stack

  • Go 1.23+
  • chi router (NOT gin, gorilla, fiber)
  • sqlc for type-safe queries
  • Postgres 16
  • pgx driver
  • testify for assertions

Code style

  • gofmt (no exceptions)
  • golangci-lint with our .golangci.yml
  • Filenames: snake_case
  • Errors wrapped with fmt.Errorf("doing X: %w", err)

Architecture

  • internal/ for non-public packages
  • Layers: handler → service → repository
  • handlers thin; no business logic
  • services own transactions
  • repositories use sqlc-generated code only
  • Context.Background() never in production paths

Tests

  • _test.go files alongside code
  • testcontainers-go for integration tests with real Postgres
  • t.Parallel() on every test that's safe
  • Subtests for table-driven tests

Avoid

  • Naked returns
  • init() functions (use New() constructors)
  • panic() outside main()
  • third-party ORMs (sqlc is sufficient)
  • gorm specifically
Architect/editor pairing: Opus 4.7 architect + GPT-5.4 editor. Go's verbosity benefits from a strong planner; GPT-5.4 is fast and cheap for writing the boilerplate.

Template: Rust + Axum + SQLx

# Project conventions

Stack

  • Rust 1.83+
  • Axum 0.8 (NOT actix-web or rocket)
  • SQLx with Postgres (compile-time-checked queries)
  • tokio runtime
  • tracing for logs (NOT log crate)
  • thiserror for error types

Code style

  • rustfmt
  • clippy (deny warnings)
  • snake_case filenames
  • explicit Result return types on public functions

Architecture

  • src/routes/ for handlers
  • src/services/ for business logic
  • src/db/ for SQLx queries
  • src/models/ for shared types
  • AppState as shared dependency; never globals
  • Tower middleware for auth, rate-limit, tracing

Tests

  • #[tokio::test] for async
  • testcontainers-rs for integration
  • One test module per file (inline #[cfg(test)] mod tests)
  • assert_matches for enum assertions

Avoid

  • unwrap() in non-test code (use ? or expect with message)
  • &mut self handlers in Axum (handlers consume context by value)
  • async-std (we use tokio)
  • diesel (SQLx only)
  • Box<dyn Trait> when generics would do
Architect/editor pairing: Opus 4.7 architect + Opus 4.7 editor. Rust's borrow checker creates enough write-side complexity that the editor benefits from the strong model too.

Per-stack architect/editor cheat sheet

StackArchitectEditorReason
Next.js / TSOpus 4.7Sonnet 4.7Server/client component planning is non-obvious
RailsOpus 4.7(same — no split)Small enough
DjangoSonnet 4.7Sonnet 4.7Stable conventions
GoOpus 4.7GPT-5.4Boilerplate-heavy
RustOpus 4.7Opus 4.7Borrow checker complexity
Phoenix / ElixirOpus 4.7Sonnet 4.7Less common in training; needs planner
FlutterOpus 4.7Sonnet 4.7Widget tree planning
SwiftUIOpus 4.7Opus 4.7Apple API churn

What CONVENTIONS.md should NOT contain

Five things we see in CONVENTIONS.md files that don't belong there:

Tutorial-style explanations. "We use Next.js because it has SSR." aider doesn't need to know why; aider needs to know what to do. Skip the rationale. Secrets or credentials. This file is checked in (or should be). Never put API keys here. If aider needs them, env vars. Long code examples. A 200-line example component bloats the context. Use 5-line examples or none. The conventions are rules; the rules don't need to be illustrated with full implementations. Personal preferences not enforced by tooling. "I like 4-space indents" doesn't matter if Prettier auto-formats. Put it in your formatter config and don't repeat it here. Repetition wastes tokens. Aspirational rules. "We always write tests first." If the codebase doesn't actually have tests-first patterns, the rule will be ignored after the first few invocations. Match what your codebase actually is, not what you'd like it to be.

AGENTS.md migration

If your project uses multiple AI coding agents (aider + Cursor + Claude Code + Codex CLI), maintain AGENTS.md as the authoritative file and have aider read it. Two options:

Option 1 — symlink:
ln -s AGENTS.md CONVENTIONS.md
Option 2 — explicit:

In your .aider.conf.yml:

conventions: AGENTS.md

aider v0.55+ auto-discovers AGENTS.md too. The file format is identical — same five sections, same content. See /topic/agents-md for the cross-tool story.

Where this fails

Conventions drift. As the codebase changes, CONVENTIONS.md gets stale. We see this commonly with "we use X" lines where X was deprecated 6 months ago. Audit quarterly. Templates are starting points. The above templates are what we'd ship as a v1; your team will customize each. The customization is the part that matters. Some conventions need code, not docs. "Always use prepared statements" is good in CONVENTIONS.md but better as a lint rule. If you can enforce a convention mechanically, do that — the doc-level convention is for things tooling can't catch. 60 lines is opinionated. HumanLayer's 60-line standard is empirical (frontier models reliably follow about that much), not absolute. Some teams ship 200-line files and they work. Iterate based on what your team's aider sessions actually produce. aider's two-mode pricing assumes API access. Architect/editor pairings save cost when both models go through paid APIs. If you're on Claude Max / Pro for the architect, the cost calculus is different — Claude Max has no per-token cost for the user, so "save cost" isn't a benefit. Use single-model in that case.

What to read next

Sources

Frequently asked

Where does aider look for CONVENTIONS.md?
Three locations in priority. (1) ~/.aider/CONVENTIONS.md for user-global conventions. (2) CONVENTIONS.md at the repo root for project-wide. (3) A path passed via the --conventions flag. aider also auto-discovers AGENTS.md as of v0.55+ — same file as Codex CLI and others use, see /topic/agents-md.
How is CONVENTIONS.md different from CLAUDE.md or AGENTS.md?
Same shape, different tool. CLAUDE.md is Claude-Code-only. AGENTS.md is the tool-agnostic standard (Cursor, Codex CLI, Gemini CLI, Windsurf, aider, Zed, Warp, RooCode). CONVENTIONS.md is aider-specific — older convention. If you use aider as part of a multi-tool workflow, prefer AGENTS.md. If aider is your only tool, CONVENTIONS.md works fine. They're parseable interchangeably.
What should I put in CONVENTIONS.md?
Five things. (1) Tech stack (versions matter — 'TypeScript 5.6' not just 'TypeScript'). (2) Code style preferences (formatter, linter, indent). (3) Architectural patterns (how state flows, where validation lives). (4) Test conventions (framework, file naming, what to mock). (5) What NOT to do (libraries to avoid, deprecated patterns). Aim for 60-120 lines. Under-specifying loses precision; over-specifying wastes context.
How big should CONVENTIONS.md be?
HumanLayer's standard is under 60 lines for CLAUDE.md and the same principle applies to CONVENTIONS.md. aider's docs cap at 300 lines as a practical maximum. The 60-line standard is from observation that frontier models handle ~150-200 instructions reliably; beyond that, later instructions get dropped during longer sessions.
Should CONVENTIONS.md cover security policies?
Yes, briefly. 'Never log secrets. Sanitize all user input. Use parameterized queries.' is enough for the model to know which way to bias. Detailed security policies belong in a separate SECURITY.md that the agent reads when relevant — putting them in CONVENTIONS.md crowds out the always-on space.
What's the architect/editor mode in aider?
aider's two-mode workflow. Architect mode uses a stronger (more expensive) model to plan; editor mode uses a cheaper, faster model to write. Common pairing: Claude Opus 4.7 architect + GPT-4o or Sonnet 4.7 editor. The architect's CONVENTIONS.md context flows down to the editor. Useful for keeping cost manageable while preserving plan quality.

Related topics