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:
- Stack and versions — what we use, what version
- Code style — formatter, linter, naming
- Architecture — how state flows, where validation lives
- Tests — framework, conventions, mocking policy
- Avoid — what NOT to do
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
| Stack | Architect | Editor | Reason |
|---|---|---|---|
| Next.js / TS | Opus 4.7 | Sonnet 4.7 | Server/client component planning is non-obvious |
| Rails | Opus 4.7 | (same — no split) | Small enough |
| Django | Sonnet 4.7 | Sonnet 4.7 | Stable conventions |
| Go | Opus 4.7 | GPT-5.4 | Boilerplate-heavy |
| Rust | Opus 4.7 | Opus 4.7 | Borrow checker complexity |
| Phoenix / Elixir | Opus 4.7 | Sonnet 4.7 | Less common in training; needs planner |
| Flutter | Opus 4.7 | Sonnet 4.7 | Widget tree planning |
| SwiftUI | Opus 4.7 | Opus 4.7 | Apple 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:
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
- /topic/agents-md — the cross-tool standard
- /topic/claude-md — the Claude-Code-specific parallel
- /topic/local-ai-coding — aider with Ollama / local models
- /topic/cursor-rules-typescript-5-6 — Cursor's equivalent
- /topic/cursor-rules-nextjs-15 — Cursor template for the same stack
- /topic/spec-driven-development — when to add Spec Kit on top
- /for/solo-developers — single-engineer workflows where aider shines
Sources
- aider. "Specifying coding conventions". The official CONVENTIONS.md spec.
- aider. paul-gauthier/aider repository. 30k+ stars.
- AGENTS.md. "The AGENTS.md specification". Linux Foundation Agentic AI Foundation steward.
- HumanLayer. "Writing a good CLAUDE.md". The 60-line standard.
- HN 44957443. "AGENTS.md launch thread". 382 comments on the standardization debate.
- HN 47183167. "Show HN: I got tired of syncing Claude/Gemini/AGENTS.md and .cursorrules". Sync-pain pattern.
- HN 46809708. "AGENTS.md outperforms skills in our agent evals". Counter-narrative.
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.