Topic 01

The Project Instructions File

Setup

Every session starts empty, so the agent meets your codebase the way a new colleague would on their first day, every day. The project instructions file is the briefing for that day: a short text file, committed to the repository, that the agent loads into its context at the start of every session, before your first message.

What goes in it, and what stays out, decides what every session knows without being told. A good one prevents the same wrong diff from being written fifty times. A bad one, long, vague or out of date, is read just as faithfully and does damage in proportion.

What It Is

It is a plain text file, usually Markdown, at the repository root. It is committed and reviewed like code, and the harness reads it automatically when a session starts. As of 2026 several tools read one shared file name, and others use a name of their own; Chapter 15 names them. Some tools also read a file per directory, and the nearest one to the code being edited applies, so a subdirectory with its own rules can carry its own short file.

The content and the habits are the same whatever the file is called. If your team uses tools that expect different names, keep one real file and point the others at it, rather than maintaining two copies that drift apart.

Keep the project file separate from your personal preferences. How you like the agent to phrase its summaries, or which editor you use, is not a fact about the repository, and it belongs in a personal file that only your sessions load. The project file is what every engineer's sessions and every cloud agent working on the repository share, so it is reviewed like code and says only what is true for all of them. Chapter 4 covers the personal file and the notes some tools save between sessions.

What Goes In

The test for every line is whether a capable colleague could work it out from the code in ten minutes. If they could, leave it out. If they could not, it belongs here. That leaves four kinds of content.

First, the commands to build, test, lint, format and run the service, exactly as typed, which the next page covers in detail. Second, conventions that are not visible in any single file. At Cragmoor, money is held in whole cents, and every class time goes through the time-zone helper in schedule; neither rule is stated anywhere in the code, and both are broken by any agent that has not been told. Third, what not to touch: generated files, the migrations directory, and the untested pricing module until it has characterization tests, which Chapter 11 writes. Fourth, where things are, in a few lines, so the agent's first search starts in the right place.

The project instructions file · booking service
# Booking service: notes for coding agents

Cragmoor's booking service: reservations, waitlists, pricing, refunds and
the class schedule for four climbing gyms in two time zones. Read this
before changing anything. If a rule here looks wrong, say so; don't work
around it.

## Commands (run from the repository root)
- Type-check:        python -m mypy src tests
- Test, everything:  python -m pytest                          (~900 tests, ~3 min)
- Test, one file:    python -m pytest tests/test_refunds.py    (seconds)
- Lint:              ruff check .
- Format:            ruff format .
- Run locally:       python -m cragmoor
The test commands start the local test database themselves. Never point
them at any other database.

## Conventions
- Money is an int number of cents. Never a float, never a string.
- Every class time goes through the time-zone helper in schedule.py.
  Never build a local time by hand: the gyms are in two time zones.
- Errors that reach the API are BookingError with a code from errors.py.
- Tests for src/cragmoor/<module>.py live in tests/test_<module>.py.

## Do not touch
- migrations/                written by hand, reviewed by Ines. Propose, never edit.
- src/cragmoor/generated/    produced from the API schema. Regenerate instead.
- src/cragmoor/pricing.py    no tests yet. Read it; change it only after
                             characterization tests exist, and ask first.

## Where things are
- src/cragmoor/booking.py    reserve and cancel a place
- src/cragmoor/waitlist.py   offers to the next climber, 15-minute holds
- src/cragmoor/refunds.py    what a cancellation gets back
- src/cragmoor/schedule.py   classes, start times, each gym's time zone
- docs/decisions/            why things are the way they are, one file each

## How we work
- One task per branch, named after the task (refund-window-12h).
- Keep a change under about 200 changed lines; split anything bigger.
- Commit messages say why. The diff already says what.

## Before you say you are done
- Format first, then lint and type-check. Leave no new warnings.
- Run the one-file test command for each module you changed, then the
  full suite. Paste the summary line of each run.
- Do not push, deploy or add dependencies. Say what you would add and why.
The project instructions file · booking service
# Booking service: notes for coding agents

Cragmoor's booking service: reservations, waitlists, pricing, refunds and
the class schedule for four climbing gyms in two time zones. Read this
before changing anything. If a rule here looks wrong, say so; don't work
around it.

## Commands (run from the repository root)
- Type-check:        npx tsc --noEmit
- Test, everything:  npx vitest run                            (~900 tests, ~3 min)
- Test, one file:    npx vitest run tests/refunds.test.ts      (seconds)
- Lint:              npx biome lint .
- Format:            npx biome format --write .
- Run locally:       node src/main.ts
The test commands start the local test database themselves. Never point
them at any other database.

## Conventions
- Money is an integer number of cents. Never a fractional number, never a string.
- Every class time goes through the time-zone helper in src/schedule.ts.
  Never build a local time by hand: the gyms are in two time zones.
- Errors that reach the API are BookingError with a code from src/errors.ts.
- Tests for src/<module>.ts live in tests/<module>.test.ts.

## Do not touch
- migrations/        written by hand, reviewed by Ines. Propose, never edit.
- src/generated/     produced from the API schema. Regenerate instead.
- src/pricing.ts     no tests yet. Read it; change it only after
                     characterization tests exist, and ask first.

## Where things are
- src/booking.ts     reserve and cancel a place
- src/waitlist.ts    offers to the next climber, 15-minute holds
- src/refunds.ts     what a cancellation gets back
- src/schedule.ts    classes, start times, each gym's time zone
- docs/decisions/    why things are the way they are, one file each

## How we work
- One task per branch, named after the task (refund-window-12h).
- Keep a change under about 200 changed lines; split anything bigger.
- Commit messages say why. The diff already says what.

## Before you say you are done
- Format first, then lint and type-check. Leave no new warnings.
- Run the one-file test command for each module you changed, then the
  full suite. Paste the summary line of each run.
- Do not push, deploy or add dependencies. Say what you would add and why.
The project instructions file · booking service
# Booking service: notes for coding agents

Cragmoor's booking service: reservations, waitlists, pricing, refunds and
the class schedule for four climbing gyms in two time zones. Read this
before changing anything. If a rule here looks wrong, say so; don't work
around it.

## Commands (run from the repository root)
- Compile + type-check:  ./gradlew compileJava compileTestJava
- Test, everything:      ./gradlew test                        (~900 tests, ~3 min)
- Test, one class:       ./gradlew test --tests '*RefundsTest' (seconds)
- Lint:                  ./gradlew checkstyleMain checkstyleTest
- Format:                ./gradlew spotlessApply
- Run locally:           ./gradlew run
The test commands start the local test database themselves. Never point
them at any other database.

## Conventions
- Money is a long number of cents. Never a double, never a String.
- Every class time goes through the time-zone helper in Schedule.java.
  Never build a local time by hand: the gyms are in two time zones.
- Errors that reach the API are BookingException with a code from ErrorCode.
- Tests for <Module>.java live in <Module>Test.java, same package.

## Do not touch
- src/main/resources/db/migration/         written by hand, reviewed by Ines. Propose, never edit.
- build/generated/                         produced from the API schema. Regenerate.
- src/main/java/org/cragmoor/Pricing.java  no tests yet. Read it; change it only after
                                           characterization tests exist, and ask first.

## Where things are (under src/main/java/org/cragmoor/)
- Booking.java       reserve and cancel a place
- Waitlist.java      offers to the next climber, 15-minute holds
- Refunds.java       what a cancellation gets back
- Schedule.java      classes, start times, each gym's time zone
- docs/decisions/    (repository root) why things are the way they are

## How we work
- One task per branch, named after the task (refund-window-12h).
- Keep a change under about 200 changed lines; split anything bigger.
- Commit messages say why. The diff already says what.

## Before you say you are done
- Format first, then lint and type-check. Leave no new warnings.
- Run the one-class test command for each class you changed, then the
  full suite. Paste the summary line of each run.
- Do not push, deploy or add dependencies. Say what you would add and why.

Read the file above section by section. The commands come first because they turn the agent's claims into evidence. The conventions are the rules that, while unwritten, produced wrong diffs in the team's first month with an agent. The do-not-touch list carries a reason on every line, so the agent can apply it to a case the line did not foresee. The last two sections set the team's working habits and tell the agent what "done" means at Cragmoor, which it would otherwise decide for itself.

Cragmoor's instructions file, about 50 lines, by section
SectionLinesWhat it holds
Commands9build, test, one test, lint, format, run, exactly as typed
Conventions6rules no single file shows: cents, the time-zone helper, errors
Do not touch5files out of bounds, each with its reason; backed by permissions
Where things are6a map for the first search, not a description of each module
How we work4one branch per task, changes under about 200 lines, commit messages that say why
Before you say you are done5what "done" means here: which checks, which tests, what not to do

What Stays Out

Anything the code already says stays out: a paragraph describing what each module does, the list of endpoints, the data model. The agent can read the code, and a description written in March is wrong by June. Anything one search finds stays out. Aspirations nobody enforces stay out: "write clean code" and "follow best practices" change no behaviour, because no agent was planning to write dirty code. Secrets of any kind stay out, because the file is committed and loaded into every session. And long prose stays out, because every line is loaded into every session whether the task needs it or not.

That last point is the economics of the file. A line that changes no behaviour costs context and attention in every session, forever, for nothing. A line about the database migrations is paid for by every session that only touches the refund rule.

Short

The file competes with the task for the agent's attention. Fifty lines that are all followed beat 500 that are partly followed, and the way a long file fails is quiet: the three rules that matter sit among forty that do not, and adherence drops for all of them, the important ones included.

This book's rule of thumb is to stay under about 100 lines. Past that, move detail into files the instructions link to, such as a note on how the waitlist's holds work or the full list of error codes, and let the agent read them when a task needs them. A link costs one line in every session; the detail behind it costs nothing until it is used.

True

Each line of the file is a claim about the repository. "Tests live in the tests directory." "Use the time-zone helper in schedule." "Never edit the migrations directory." A false claim is worse than no claim, because the agent follows it confidently: told that tests live somewhere they no longer do, it will create a new test directory to put them in.

So every line should be checkable against the code, and checking it should be easy. When you read the file, ask of each line whether you could prove it true by looking. A line you cannot check, such as "the waitlist is thread-safe", is a hope, and the agent will treat it as a fact.

Maintained

The file changes in the same pull request as the thing it describes. When Ines moves the test directory, the instructions change in that same diff, and the reviewer reads the change to the instructions as code, because the agent acts on them as if they were. Any other schedule, a quarterly tidy-up or "whoever notices", guarantees the file is wrong for most of its life.

Treat the rules in the file as candidates for enforcement, too. "Money is an integer number of cents" can be a lint rule or a type; "tests live next to the module" can be a check in the test configuration. A rule a tool enforces fails loudly whether the agent read it or not, and it can come out of the file.

Project Instructions File vs README

The README is for a person deciding whether and how to use or contribute to the project: its purpose, setup and links. It can afford narrative, and it is read once.

The project instructions file is for an agent about to change the code: exact commands, conventions and boundaries. It is loaded into every session, so it is terse. The two overlap on commands; have one point to the other rather than keeping two copies that drift apart.

Misconceptions
  • "More instructions mean better behaviour." Every line competes with the task for attention. A long file buries the three rules that matter among forty that do not, and adherence drops for all of them.
  • "Write it once at setup." It rots as the code moves. An instruction naming a deleted directory sends the agent searching for it or, worse, recreating it.
  • "It is a security boundary." "Never edit the migrations directory" is a request the agent usually honours, not a rule anything enforces. Boundaries that must hold go into permissions and the sandbox.
  • "Put the whole architecture in it." The agent can read the code. The file is for what the code cannot tell it: commands, conventions, intent, and what is off limits.
  • "It's my personal setup." The project file is shared and reviewed like code. Personal preferences belong in a personal file that only your sessions load.
Why It Matters
  • Start with the commands, the three conventions most often broken and the files out of bounds. They prevent the most wrong diffs per line.
  • Keep it under about 100 lines and link out for detail. Every line is read in every session.
  • Change it in the same pull request as the code it describes. That is the only schedule on which it stays true.
  • Turn any rule a tool can check into a lint rule or a test instead of a line. The agent can overlook a sentence, not a failing check.

Knowledge Check

Which candidate line most deserves a place in Cragmoor's instructions file?

  • "The refunds module calculates what a cancellation gets back."
  • "Every class time goes through the time-zone helper in schedule."
  • "Write clear, well-structured code that is easy to maintain."
  • "The staging database password is in the shared vault, here."

Ines moves the tests into a new directory, but the instructions file still names the old one. What is the agent most likely to do?

  • Notice the mismatch and ask which of the two directories is right
  • Ignore the stale line, since it no longer matches the repository
  • Follow the stale line, searching for or recreating the old directory
  • Refuse to start, because the file fails a check when the session loads

The team must never let an agent edit the migrations directory. Where does that rule belong?

  • In the instructions file only, written in capital letters
  • In a permission or the sandbox, with the file saying why
  • In the README, where new contributors will be sure to see it
  • In a comment at the top of each migration file in the folder

Kai wants to copy the README's setup section into the instructions file so the agent has everything. What is the better arrangement?

  • Keep both copies and update each one by hand whenever setup changes
  • Delete the README, since the instructions file now covers everything
  • Paste the whole README in, so the agent reads all the background
  • Keep the commands in one place and have the other file point to it

Cragmoor's file has grown to 400 lines. What is the likely effect on the agent?

  • The important rules are followed less reliably among all the rest
  • The harness refuses to load a file of that length at session start
  • The agent follows more rules, since more of them are written down
  • Only the first 100 lines are read and the rest is silently dropped

You got correct