Every AI coding session starts blank. The model has no memory of your project, no knowledge of your conventions, no idea what your build command is or which libraries you prefer or what you decided six months ago when you chose this architecture. It knows how to write code in general. It does not know how to write code for your system.
This is the core problem with how most teams use AI coding tools. You open a chat, describe what you want, get code back, iterate. For small isolated tasks that's fine. It breaks down when the problem has real constraints or multiple steps, because the model is filling gaps with reasonable guesses that may have nothing to do with how your system actually works. You then spend the session correcting those guesses: "no, we use pnpm not npm," "no, don't modify the migrations directly," "no, errors go through ApiError not raw throws." Those corrections vanish when the session ends. Next session, same thing.
The fix is not better prompts. It is giving the model the context it needs. There are three ways to do that.
AGENTS.md: tell the model about your codebase once
AGENTS.md is an open standard (stewarded by the Linux Foundation, supported across Claude Code, Cursor, GitHub Copilot, Codex CLI, and Gemini CLI) for committing project context directly to your repository. Every AI tool that reads it gets the same starting point. CLAUDE.md is Claude Code's native equivalent with some additional capabilities, but Claude Code reads AGENTS.md as a fallback, so one file covers most tools.
The right mental model is a README written for an AI rather than a human. Not an exhaustive specification of everything about the project, but the specific things the model cannot infer from the code itself: build and test commands, hard constraints, architectural decisions that aren't obvious from the directory structure.
Three things that are worth knowing before you write one. First, keep it human-written and short. ETH Zurich researchers tested context files across four AI agents and found that LLM-generated files hurt performance, reducing task success rates while increasing inference cost. Human-written files showed roughly a four percentage point improvement. Auto-generate your AGENTS.md and you're paying more to get worse results. Second, don't put code style rules in it. That's your linter's job, and it does it deterministically and cheaply. Third, be aware that frontier models can follow around 150-200 instructions reliably. Claude Code's own system prompt already uses roughly 50 of those, so every line you add to AGENTS.md is competing for a finite budget. Include only what matters universally.
# AGENTS.md
## Project
E-commerce API. Node.js 22 / TypeScript strict / Fastify 5 / PostgreSQL 16 via Drizzle ORM.
## Commands
- `pnpm test` — unit tests
- `make test-integration` — integration tests (requires local DB)
- `pnpm lint` — ESLint + Prettier
## Hard constraints
- Never modify files in /migrations directly
- All handlers must validate input with Zod schemas
- API errors use ApiError class, never raw throws
- Do not modify anything in vendor/
## Architecture
- /src/api — route handlers only
- /src/services — business logic, no DB access
- /src/db — Drizzle schema and queries only
If your team uses multiple AI tools, maintain AGENTS.md as the single source of truth and have CLAUDE.md reference it with only Claude-specific additions. One file to keep current rather than several slowly drifting apart.
Spec-driven development: tell the model what you're building
AGENTS.md handles persistent project context. Spec-driven development handles the context for a specific piece of work. The idea is simple: write a spec before you ask for code. Not a lengthy design document, just an explicit statement of what the thing should do, what goes in, what comes out, and what the constraints are. Then generate code from that.
The reason this matters is that a vague prompt forces the model to make assumptions. Ask for "a function to process customer transactions" and the model will produce something plausible, but it will guess at error handling, edge cases, and output format. You iterate to correct those guesses, which is slow and produces code that reflects the model's assumptions more than your requirements. Define the inputs, outputs, deduplication rules, and error behavior upfront, and the model is executing against a contract instead of guessing. You get something usable on the first pass instead of something you spend an hour correcting
GitHub's Spec Kit formalizes this into four phases: specify (what you're building and why), plan (stack, architecture, constraints), tasks (break it into reviewable chunks), implement (the agent works through tasks one at a time). Each phase produces artifacts that feed the next, and each has a checkpoint where you review before moving on. The insight in their framing is that the spec is the primary artifact and the code is a derivative, which inverts where most teams spend their attention. You should be reviewing the spec carefully and letting the code follow from it, not the other way around.
For more complex multi-step work, the BMAD method extends this thinking across the full development lifecycle. Rather than a single spec for a feature, you work through problem definition, spec, design, and task breakdown before any code is written. Each step's output becomes the next step's input. The practical benefit is that errors get caught early: a flawed spec is much cheaper to fix than flawed code, and the model has continuity across the whole effort rather than starting fresh at each turn.
Screenshots: tell the model what you can see
For UI and visual work, screenshots are one of the most underrated tools for giving a model precise context. Describing a visual problem in words is surprisingly hard. "The button is too close to the header" is ambiguous in ways you don't realize until the model fixes the wrong button on the wrong screen. A screenshot with the element visible removes most of that ambiguity in a way that text cannot.
Claude handles image input well. The prompt pattern that works is straightforward: attach the screenshot, point at the specific element that needs to change, and describe what you want differently. Reference what you can see in the image rather than class names or component names the model may not recognize from the codebase. The same applies to design references. If you have a Figma frame or a screenshot of how something should look, attaching it is almost always more precise than trying to describe the visual in words.
The pattern
All three of these are the same idea at different levels. AGENTS.md closes the gap between the model and your project. A spec closes the gap between the model and your intent for a specific feature. A screenshot closes the gap between the model and what you can see but struggle to describe. In each case you are replacing the model's guesswork with your actual requirements.
Get this right and the model does what you actually want. Get it wrong and you spend most of your time correcting assumptions the model should never have had to make. A clever prompt on top of thin context is still thin context.