Tinker AI
Read reviews
beginner 6 min read

Aider's CONVENTIONS.md: keeping the model on script across a session

Published 2026-05-02 by Owner

Every Aider session starts fresh. The model has no memory of how your codebase wants code to look. So unless you tell it, it’ll write code in the median style of its training corpus — which is fine, except your codebase isn’t median. It has opinions, deprecated patterns, and library choices that aren’t obvious from the immediate file context.

Aider’s --read CONVENTIONS.md flag (or its newer auto-loaded variant via .aider.conf.yml) gives you a way to ship those opinions into every session. One file, loaded read-only, applied to every prompt. Done well, this drops the rate of “Aider wrote something I have to rewrite” from common to rare.

The minimal setup

In your repo root, create CONVENTIONS.md. The simplest invocation:

aider --read CONVENTIONS.md

Aider loads the file as read-only context. Every prompt you send gets the conventions appended automatically. The model can’t modify the file (read-only), and you don’t have to remember to add it.

To make this permanent, add to .aider.conf.yml at the repo root:

read:
  - CONVENTIONS.md

Now aider with no arguments loads the conventions automatically. New team members who clone the repo get the same setup without configuration.

What goes in CONVENTIONS.md

The file should be short. Long convention docs get summarized internally by the model, which means specific guidance gets lost. Aim for under 80 lines total.

A working template:

# Project conventions for Aider

## Stack

- TypeScript 5.x, strict mode on
- Next.js 14 App Router (no Pages Router)
- Postgres via Drizzle ORM
- Tailwind for styling, no CSS modules
- pnpm for package management

## Code style

- No `any`. If a type is genuinely unknown, use `unknown` and narrow.
- Async/await over `.then()`. No bare promises.
- Function components with arrow syntax: `const Foo = () => {}`.
- Single quotes in TS files, double quotes in JSX.
- Imports grouped: external → @/* aliased → relative, blank line between groups.

## Patterns we use

- Server actions, not API routes, for form submissions
- Drizzle queries colocated with their consumers, not in a `db/queries.ts` god file
- Error handling: throw typed errors, never `{ ok, error }` Result tuples
- Tests in `__tests__/` next to the file under test, not in a top-level `tests/`

## Patterns we don't use anymore

- React Query — we removed it; use server components or SWR
- Class components — convert any encountered, never write new
- `useEffect` for derived state — use `useMemo` or compute inline
- styled-components — Tailwind only

## Library choices to defer to

- `zod` for validation, not yup or joi
- `date-fns` for dates, not moment or dayjs
- `lucide-react` for icons, not heroicons or react-icons
- `bcryptjs` for hashing (not bcrypt — we deploy on edge runtime)

About 60 lines, every line load-bearing. The “Patterns we don’t use anymore” section is the most valuable — explicit deprecations stop the model from helpfully suggesting libraries you removed last quarter.

What to leave out

Three things I tried that turned out to be wasted lines:

Generic “good code” advice. “Write maintainable, readable code with clear separation of concerns.” The model already does this in some sense. The phrase doesn’t change behavior; it just adds tokens.

Architecture explanations. “We use a layered architecture with services, repositories, and controllers.” If your file structure already implies this, the model picks it up from the immediate context. If your structure doesn’t imply it, a paragraph in CONVENTIONS.md won’t fix that.

Long rationales. “We chose Drizzle over Prisma because of edge-runtime compatibility and the simpler types.” Interesting context for humans, irrelevant to model behavior. Save it for an ARCHITECTURE.md if you need it.

Project-specific quirks worth documenting

The conventions file is the right place for things that would otherwise live in tribal knowledge:

## Project quirks

- All times are stored as UTC in the DB. Frontend converts to user TZ on display.
- The `User` type has both `id` (DB primary key) and `userId` (legacy external id). Use `id` unless explicitly working with the legacy system.
- Error codes follow the format `MODULE.OPERATION_FAILED` — see src/lib/errors.ts for the full list.
- Feature flags live in `src/lib/flags.ts`. Always check via `useFlag()` hook, not direct env access.

These are the things that, when violated, produce code that compiles, passes review on first glance, and breaks subtly in production. Documenting them in CONVENTIONS.md catches the issue before the PR is opened.

How to know it’s working

The signal that conventions are landing: Aider’s first-pass output looks like the rest of your codebase. The signal it’s not: you keep manually fixing the same kinds of things across sessions, and the fixes are things in your conventions file.

When I notice a recurring fix that’s covered in my conventions, two possibilities:

  1. The conventions file is too long, and that section is getting deprioritized internally
  2. The phrasing isn’t direct enough — vague guidance gets ignored in favor of training defaults

For (1), trim. Remove anything that’s been read 50 times without being violated and is obviously already happening — those lines are wasted budget.

For (2), rephrase as commands rather than descriptions. “We prefer arrow function components” reads as a soft preference. “Use arrow function syntax for all components. Never use function Foo().” reads as a rule.

Versioning and review

CONVENTIONS.md should be in git, reviewed like code, and updated when a new pattern lands. Treat changes to it as worth a PR review — they affect every Aider session every developer runs after the merge.

A weekly habit that’s helped: Friday afternoon, look at the week’s PRs for repeated comments along the lines of “we don’t do this here.” Each one is a candidate for a new line in CONVENTIONS.md. Adding it once is cheaper than re-explaining in every code review.

Limits

Conventions in CONVENTIONS.md are guidance, not enforcement. The model follows them most of the time, ignores them occasionally, and can’t be made perfectly compliant via prompting alone. For things that actually have to be enforced — security boundaries, license rules, output formats consumed by other systems — use linters, type checks, or CI gates.

The conventions file reduces friction. It doesn’t replace verification.