The thousand-line prompt problem
Every team using AI agents seriously ends up with a giant instructions file. It works, briefly, and then stops, for a reason worth understanding.
The progression is almost universal. You start with a sentence. The agent does something you did not want, so you add a line explaining not to. That happens again. Six weeks later there is a file in your repository with four hundred lines of accumulated instruction, and someone on the team refers to it, not entirely as a joke, as the constitution.
This is a reasonable response to a real problem, and it does work, up to a point. The point is closer than most teams expect.
Why the file grows
Each line in it is a scar. Something went wrong once, and the line is there to stop it happening again:
Always use the existing validation helper, do not write a new one.Never call the payments service from a component.Database migrations go in the migrations folder, one per change.Do not add a dependency without asking.
Every one is sound. Every one is also a rule about the architecture, written in English, stored where nothing can check it.
The three ways it caps out
1 · Attention is finite
A four-hundred-line instruction file competes with the actual task for the model's attention. Rule 200 gets less weight than rule 3. As the file grows, the marginal rule does less, and eventually adding rules stops helping measurably.
2 · English is not checkable
"Never call the payments service from a component" is a rule a machine could enforce trivially, if it were expressed as a rule rather than as a sentence. As prose it is a suggestion with good intentions. Nothing fails when it is violated. You find out in review, if the reviewer remembers it exists.
3 · It describes without depicting
The file tries to convey the shape of a system in paragraphs. Architecture is a graph of parts and the connections between them, and prose is a bad encoding for graphs. This is why the file keeps needing new lines: each one patches a case the previous prose failed to imply.
The instructions file is doing two jobs
Separating them is most of the fix, because they want completely different homes.
| Job | Example | Belongs in |
|---|---|---|
| Orientation | "The API is in this folder, tests run with this command" | Prose. This is genuinely what a text file is for. |
| Constraint | "Components must never import payments directly" | A machine-checkable rule that fails a build. |
| Structure | "These are the services and how they connect" | A typed graph, generated from and compared to the code. |
Keep the first. It is short, stable, and rarely needs updating. It is the second and third that grow without limit when they are trapped in prose, and both have better encodings.
Replacing prose with structure
Extract the constraints
Go through the file and mark every line that is really a rule about what may talk to what. In most files this is a third to a half of the content.
Make them fail something
Dependency-rule tooling exists for most ecosystems and will enforce module boundaries directly. A rule that fails a build does not need to be repeated to anyone, ever.
Give the structure a real form
The parts of the system and their connections belong in a typed map that is derived from the code, not in a paragraph that describes it from memory.
Keep what is left
What remains is orientation: genuinely useful, and now short enough that a model reads all of it.
Graphlit is built on that split. The architecture is a drawing, which becomes a typed graph. Rules are declared on the graph and enforced on every change: this may only be reached through that, these two must never talk directly, this layer may not call that one. What is left over for prose is the orientation, which is a page rather than a constitution.
- gate_not_wired
Auth check exists but nothing calls it
lib/auth.ts → app/api/payments/route.ts
- stub_shortcut
Refund handler returns success without refunding
app/api/refunds/route.ts
- duplicate_endpoint
Two handlers answer POST /api/checkout
app/api/checkout/route.ts
- orphan_file
Nothing imports this module
lib/legacy-cart.ts
- isolated_node
Receipts is drawn but connects to nothing
graph node · service:receipts
Hypotheses until an agent pass confirms them. A scanner that overstates its confidence gets ignored.
A rule you have to repeat is not a rule. It is a hope with a paragraph number.
A note on the irony
Graphlit exists to delete the thousand-line prompt, which would make it embarrassing for this site to need a thousand words per page to explain itself. There is a word budget in the build that fails if a marketing page goes over. The articles are exempt, because someone searching for a comparison wants the full answer.
The general principle holds either way: if something has to be explained at length repeatedly, the explanation is not the fix. The structure is.
Common questions
Are AI instruction files like CLAUDE.md or cursor rules a bad idea?
No. They are genuinely useful for orientation: where things live, how to run the tests, what the conventions are. The problem is only when they take on architectural constraints, because prose cannot enforce anything and the file grows without limit.
How long should an AI instructions file be?
Short enough that you would expect someone to read all of it. If it has grown past that, the excess is usually constraints that want to be automated checks rather than sentences.
Why do AI agents ignore instructions?
Rarely outright defiance. Usually attention. A long instruction file competes with the task itself, so later rules carry less weight. If a rule matters enough that ignoring it breaks something, it should fail a build rather than live in a paragraph.
Draw it. Then keep it true.
Graphlit turns an architecture drawing into a typed graph, builds against it, and proves the code still matches. Free to start.