Agent Engineering
Module 05 · Steering/Lesson 5.1/3 min

The project brief

One file, checked into the repo, loaded at session start. The highest-leverage artifact in this course.

Every correction you make twice is a bug in your setup. The fix is a file the harness loads into context at the start of every session — commonly AGENTS.md, sometimes CLAUDE.md, .cursorrules, or a config key. Names differ; the concept does not: the project's standing brief.

Write it from evidence

Do not write it from imagination. Open the scratch log from Lesson 3.7 and read back every correction you tagged GENERAL. Those are things the agent got wrong that it would get wrong again. That list, cleaned up, is your first brief.

from log to brief
log:   "had to say: use the existing Result type, not exceptions"
brief: Errors are values. Return Result<T, E> from src/lib/result.ts.
       Do not throw except at process boundaries (src/server/entry.ts).

log:   "had to say: tests go in __tests__, not next to source"
brief: Tests live in __tests__/ mirroring the source path. Never alongside.

log:   "had to say: the retry cap is 5, see config/queue.ts"
brief: Queue behaviour is configured in config/queue.ts. Read it before
       changing anything under src/queue/.

Notice the third one: it does not restate the value, it points at the primary source. That is the pattern that keeps a brief from going stale, and Lesson 5.3 develops it.

A working skeleton

AGENTS.md
# Project brief

## What this is
One paragraph. What the system does and who uses it.

## Commands
- check:  npm run check     (types + lint + fast tests; run before reporting done)
- test:   npm test -- --run
- dev:    npm run dev

## Conventions that are not obvious from the code
- Errors are values (src/lib/result.ts). Throw only at process boundaries.
- Tests in __tests__/, mirroring source paths.
- No default exports.
- Dates are always UTC at rest; convert only at the UI boundary.

## Where things live
- HTTP handlers: src/server/routes/
- Domain logic:  src/domain/       <- no framework imports allowed here
- Persistence:   src/db/           <- see db/README.md before changing schema

## Rules
- Never add a dependency without asking.
- Never edit files under db/migrations/ that are already applied.
- If the check command will not pass after 3 attempts, stop and report.

## Known rough edges
- src/legacy/billing.ts predates the Result convention. Do not "fix" it as
  part of unrelated work.

Check it in

The brief belongs in version control, reviewed like code. A brief that lives in one person's local settings means two teammates get different behaviour from the same task — and it evaporates when someone new joins.

Watch out

Editing the brief mid-session does not usually reload it, and it busts the prefix cache (Lesson 2.2). Edit, then clear, then start fresh. Verify the reload actually happened by asking the agent to quote a line from it.

Try it

Write your first brief from your log. Keep it under 60 lines. Then re-run the Lesson 1.5 baseline question in a fresh session and count wrong claims again. The delta is what steering just bought you.

Takeaways

  • Every repeated correction is a missing line in the brief.
  • Write it from your log, not from imagination.
  • Check it into the repo so behaviour is a property of the project, not the person.
Why point at config/queue.ts rather than writing the retry cap into the brief?

Because the brief is a secondary source and the config file is primary. A value copied into the brief will drift the first time someone changes the config, and then the agent has two conflicting sources and will believe the shorter one. Pointers stay true; copies rot.

A course by Pieter Zandbergen