Skip to content
Chapter 28Lesson 3

Writing a project AGENTS.md

Beside the lockfile you just read sits one more file at the repo root: a plain Markdown file called AGENTS.md. When someone clones this repo cold — a teammate on their first morning, or a coding agent you point at the project — what is the one file they should read before anything else?

That file is AGENTS.md. It is an open spec, not a vendor format, and the major coding agents — Codex, Cursor, Claude Code, Factory — read it natively, with no configuration. A human opens it first; an agent opens it because reading AGENTS.md is wired into how it starts work. Either way, it is the front door.

The framing this course holds is the whole discipline in one sentence: AGENTS.md is operational onboarding, not architectural prose. It carries the durable facts the next contributor needs to be productive in their first session — what the project is, what it runs on, where things live, the commands they will type — and nothing else. The moment it tries to be a design document or a tour, it starts to rot.

This is the from-scratch project, so this is where AGENTS.md gets written for the course, and every later project chapter carries the pattern forward.

This is not an excerpt. It is the project’s complete onboarding document, and it fits on a single screen:

AGENTS.md
# AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

That length is the lesson. Handed this file, a junior tends to read its brevity as incompleteness and starts padding it out, when the brevity is exactly the point.

Five sections, none wasted. Here they are at a glance; the question for each is whether the agent or the new teammate would be slower without it, and whether this is the most authoritative place for it to live.

AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

The thesis line. One sentence naming what the project is. Without it, a contributor infers the domain from filenames, and an agent that guesses wrong wires its first change against the wrong mental model. One sentence is the whole budget: this is a marketing surface, not a novel.

AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

Stack core, pinned. The load-bearing libraries, with versions where the version changes the answer. An agent that does not know it is Next.js 16 will hallucinate a pages-router API or a Tailwind v3 config and confidently write code that does not belong here. In the later database-backed projects, the Drizzle version would sit here too.

AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

Repo layout, by directory. One line per directory on what lives there, so the reader skips clicking through the tree to find components versus hooks versus fixtures. Note that it lists directories, not files. That cut is deliberate, and the next section is where it pays off.

AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

Daily commands. The exact commands a contributor types, so an agent does not default to npm run … and break the pnpm discipline from the previous lesson. pnpm verify is named as the gate: Biome CI plus typecheck plus build, the one “is this shippable?” command everyone runs before landing a change.

AGENTS.md
A static, themed marketing surface — the from-scratch toolchain project that every later project carries forward.
## Stack core (May 2026)
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 (CSS-first) · shadcn/ui · next-themes.
## Repo layout
- `src/app/` — App Router: `layout.tsx`, `page.tsx`, `globals.css`, `_components/providers.tsx`.
- `src/components/` — section components; `src/components/ui/` holds shadcn primitives.
- `src/hooks/` — custom hooks.
- `src/lib/``data.ts` fixtures and `utils.ts` (`cn()`).
- `tests/lessons/` — one `Lesson <n>.test.ts` per implementation lesson; `scripts/test-lesson.mjs` runs one file.
- `public/` — static assets.
## Daily commands
- `pnpm dev` — run the dev server.
- `pnpm build` — production build.
- `pnpm check` — Biome format + lint + organize imports (writes).
- `tsc --noEmit` — typecheck.
- `pnpm verify` — Biome CI + typecheck + build (the gate).
- `pnpm test:lesson <n>` — run a single lesson test.
## Conventions
Code style is enforced by `biome.json`; TypeScript strictness by `tsconfig.json`; editor settings by `.editorconfig`.

Conventions, as pointers. One sentence that restates no rule, only says where the rules live: biome.json for code style, tsconfig.json for strictness, .editorconfig for editor settings. This single line is the whole bloat-prevention discipline in miniature.

1 / 1

You will meet two of those convention files shortly: tsconfig.json gets its own walkthrough next lesson, biome.json the one after. The point of the Conventions section is that AGENTS.md names all three and explains none of them, and that restraint is what we turn to next.

AGENTS.md has one failure mode: bloat. A 2026 study measured agent task success across real repositories and found that LLM-generated context files actively reduced it — the model did worse with the auto-written file than with no file at all — and that even hand-written files helped only when they were minimal and precise. A padded AGENTS.md is worse than none. Every line that does not earn its place is dead weight the next reader, human or machine, has to wade through to reach the lines that matter.

So as much of the work is deciding what to keep out. Treat the following as hard exclusions:

  • Aspirational architecture statements. “This codebase strives to be clean and maintainable” tells the reader nothing they can act on or verify. Cut it.
  • Marketing copy. What the product does for customers is the README’s job, or the landing page’s, not this file’s.
  • Tutorials. The agent does not need to be taught Next.js; it needs to know which Next.js this repo runs, and the Stack core already gives it that one line. A primer here is pure noise.
  • Anything that duplicates a more authoritative source. biome.json owns the formatting rules. The moment AGENTS.md restates one, you have two copies that will disagree the first time either changes, and the reader cannot tell which is real. This is why the Conventions section is a single pointer sentence.
  • Hand-maintained file trees. A tree listing every file is stale the instant someone adds one, and nobody updates prose when they do. List directories, which capture the architectural shape and rarely change; never individual files, which drift. This is why the Repo layout section stops at the directory level.
  • Decisions that belong in an ADR. A real architectural decision — why this database, why this boundary — wants its own Architectural Decision Record, with the context and trade-offs behind it. AGENTS.md points at the ADR directory if one exists; it never inlines the decision.

Here is a fragment that breaks several of these at once. None of it is wrong, exactly — it is all just dead weight, and you can feel the difference against the tight file above.

AGENTS.md (what not to do)
# AGENTS.md
Welcome! This codebase strives to be clean, maintainable, and a joy to work in.
We believe in best practices and writing code we can be proud of. Our mission is
to delight users with a beautiful, blazing-fast marketing experience.
## Formatting
Always use 2-space indentation and single quotes. Keep lines under 80 characters.
Sort your imports alphabetically and remove unused ones before committing.
## Every file
- src/components/site-header.tsx
- src/components/hero.tsx
- src/components/feature-card.tsx
- src/components/feature-grid.tsx
- src/components/pricing-card.tsx
(… and so on for every file in the project)

The aspirational opening says nothing actionable. The Formatting section restates rules biome.json already owns and will silently diverge from. The file list went stale the moment Lesson 7 added a component, and no one will keep it current. Three sections of dead weight, and the file is already harder to use than the thirty-line original.

One test decides every line, and it carries over to any doc you write after this one:

Each of the five sections passes by construction: the thesis, pinned stack, layout, commands, and conventions pointer all describe things that change only on a deliberate decision, never on routine work.

The test also sets the size limit. The file should fit on one screen. If it grows past two while you write it, that is the signal that sections are creeping in the six-month test would reject — so apply the test to each one and cut what fails, on the spot, rather than trimming later.

You will meet other names for this file: a CLAUDE.md, a .cursorrules, a tool’s own format. The 2026 consensus is AGENTS.md as an open spec, and the course commits to it. Tool-specific files can sit alongside it, but they should reference or re-export AGENTS.md rather than keep their own copy — the same duplication discipline you applied to the Conventions section, one level up. This repo does exactly that: its CLAUDE.md is a single line, @../AGENTS.md, importing the real file instead of forking it. One source of truth, however many front doors point at it.

You can now read this project’s AGENTS.md, justify every line, and judge any other you are handed against a single test. Next you will open the first file it points at: tsconfig.json, and the two owners that share it.