Somewhere in the last year, every developer who uses AI coding agents had the same realization: you are now the code reviewer for an infinitely patient junior developer who never gets tired, never gets offended, and never remembers anything you told it. Every session starts from zero. Every rule you taught it yesterday has to be taught again today.
Fabien Sanglard, the game-engine developer behind the code for games like Star Blood Arena and the author of the Game Engine Black Book series, wrote about exactly this loop last week. His post, "My agent.md to improve LLM-assisted code quality," spent days on the Hacker News front page and collected a discussion worth reading twice. His solution is simple: stop repeating yourself in chat, and start writing the rules into a file the agent loads at the start of every session.
If you work in Java and Spring Boot, most of his rules transfer directly. A few of them are things your toolchain should already enforce. And a couple need rewriting for the specific failure modes agents produce in enterprise Java codebases. That translation is what this article is.
What agent.md actually is
The mechanism is boring, which is why it works. When a coding session starts, the harness (Claude Code, Antigravity, Codex, Cursor) loads a file from the repo root, agent.md in Sanglard's setup, AGENTS.md in the cross-vendor convention that OpenAI, Cursor, and Zed now support, CLAUDE.md for Claude Code specifically, and injects its contents into the prompt before your first message. Whatever is in that file is treated as standing instructions for the whole session.
Sanglard's origin story will feel familiar. He first tried LLM-assisted coding in mid-2025 on an mDNS implementation in Rust and got code that would not compile. By January 2026 the models had improved enough to write a complex indexed-binary heap and even pinpoint an obscure bug in a Windows IOCP code path. But the quality was, in his words, spaghetti with no comments and no structure. The speed gain was lost to cleanup. So he found himself typing the same review comments every session: no magic numbers, add a comment explaining why, use short function names. Moving each comment into agent.md once, instead of typing it a hundred times, was the whole idea.
The rules that transfer to Java unchanged
Sanglard's list is short on purpose. These are the ones I would keep word-for-word in a Java repo:
-
No magic numbers or strings. Extract recurring or meaningful values into constants or enums. If a value comes from a spec, like HTTP 200 or an ISO-8601 date pattern, use a named constant regardless. Agents love inlining
0.02in a fee calculation and re-inlining a slightly different0.02three lines later. -
Enums over booleans for parameters.
process(order, Remedy.SKIP)beatsprocess(order, true)forever. In Java this is doubly true because IDEs and the compiler will flag invalid enum values at the call site, and the agent sees the error before you do. -
Braces always, even on one-line ifs. In Java this is close to a religious matter, but with agent-generated diffs it stops being about style: a one-line
ifis exactly where an agent later appends a second statement and the indentation lies about what executes. -
Early returns over the Arrow Anti-Pattern. Agents nest. Ask any agent to add a validation to an existing method and it will happily add a fourth level of indentation inside the happy path. A written rule nudging toward guard clauses and
continuekeeps methods reviewable. - Do not touch unrelated code. Sanglard's rule: minimize changed lines, do not add comments to blocks you did not create or modify. Anyone who has reviewed an agent PR that reformatted half a file to "help" knows why this rule earns its place.
- Treat visibility changes as breaking design shifts. Fields and methods stay private unless external access is strictly required, and the agent must ask before widening anything. In a Spring codebase this is the difference between a service that stays cohesive and one where every class leaks its guts.
- Bug fix means test first. If the prompt says a bug is being fixed, the agent writes the failing test, watches it fail, writes the fix, watches it pass. This is the single highest-value rule in the whole file for Java teams, because JUnit gives the loop teeth.
The rules Java should enforce with tools instead
The most upvoted insight in the Hacker News thread came from a commenter pointing out that a chunk of Sanglard's file should be linting, so that human-written code gets the same feedback. They are right, and in Java we are spoiled for choice:
- Braces on one-line ifs, function name length, member ordering: Checkstyle rules. A model sees the CI failure and self-corrects before you ever look at the PR. A rule enforced by a linter never suffers from context dilution.
-
Layer boundaries: Sanglard's rule that each layer only talks to its immediate neighbor, no controllers calling raw SQL, is exactly what ArchUnit enforces as a test.
layeredArchitecture().layer("Controller").mayNotBeAccessedByAnyLayer().layer("Service").accessedByLayers("Controller")...turns an instruction an agent can forget into a build failure it cannot ignore. -
No magic numbers: Checkstyle's
MagicNumbercheck exists and has for twenty years.
My working rule after maintaining agent configs for a while: anything a linter can enforce, move out of AGENTS.md and into CI, then keep one line in AGENTS.md telling the agent to run the checks before declaring done. Instructions compete for attention; build failures do not.
A Java and Spring Boot adaptation
Here is the adaptation I would start from. It is Sanglard's structure with the lint-enforceable items pointed at tooling, and three additions specific to Spring Boot agent failure modes: constructor injection, no field @Autowired, and no swallowing of exceptions. Full credit to Sanglard's original, linked above, for the skeleton.
# AGENTS.md
## Style
- Run `mvn verify` before claiming a task is done. Fix what fails.
- No magic numbers or strings. Constants or enums. Spec-derived
values (HTTP codes, date patterns) get named constants too.
- Enums over booleans for parameters.
- Braces always, even on one-line ifs. Guard clauses over nesting.
- Do not modify code unrelated to the task. Minimize the diff.
- Keep fields and methods private. Ask before widening visibility.
- Short comments explaining what and why, not how.
## Java and Spring Boot
- Constructor injection only. Never field @Autowired.
- Keep @Transactional on service methods, never on private methods.
- Never swallow exceptions or catch-and-return-null. Either handle,
rethrow, or let it propagate to the advice layer.
- Services expose domain operations. Controllers never touch
repositories directly; route through the service layer.
- DTOs at the boundary. Entities do not leave the service layer.
- No println. Use the SLF4J logger that is already there.
## Process
- Bug fix: write the failing JUnit test first, watch it fail,
then fix, then watch it pass.
- Commit messages: imperative subject under 50 chars, body
explains what and why, never how.
- When unsure between two designs, stop and present both
with trade-offs instead of picking silently.
The last line matters more than it looks. The biggest review time sink is not bad style, it is an agent committing to a design decision you would have vetoed, then building three more classes on top of it.
Context dilution, and the two fixes that actually work
Instructions fade as the session grows. Sanglard cites the "Lost in the Middle" phenomenon: as context grows, models pay less attention to what sits in the middle, favoring the beginning and end. Your AGENTS.md rules are exactly the kind of content that stops being obeyed forty turns into a refactoring session. His two mitigations are refreshingly cheap:
-
Keep sessions short. One feature per session. A new session reloads
agent.mdwith full attention. - Say "reload agent.md" when you notice quality dropping. That is the whole command.
I would add a third for Java teams: put your biggest rules where dilution cannot reach them, in Checkstyle and ArchUnit, per above. A rule in a linter has no attention curve.
Tricks from the thread worth stealing
The Hacker News discussion is a catalog of community refinements. Three stood out:
- Positive phrasing. One long-time agent user argued that "don't do X" pre-seeds the model with X; "do Y, for this reason" shapes the same behavior without planting the failure mode. Rewrite your prohibitions as instructions where you can.
-
The convergence rule. Another commenter's entire
AGENTS.mdis one rule: every substantial task must end in exactly one of three states. A, success, the capability works in the real path. B, meaningful progression, one genuine blocker removed and stated. C, blocked, with the specific reason. No task ends in vague half-done. For overnight agent runs against a real codebase, this rule alone changes your morning. - Simplified English. One line, "Always use ASD-STE100 Simplified Technical English," reportedly collapses agent verbosity in comments and commit messages. Your mileage will vary, but it costs one line to test.
Does any of this measurably help?
Honestly, the rigorous evidence is thin but pointing the right way. A 2026 evaluation of repository-level context files (paper) found LLM-generated context files improved agent performance by about 2.7% on average, and in repositories with little or no documentation they beat developer-written docs. Two-point-seven percent will not sell a keynote, but the honest framing is this: instruction files are cheap, they compound over every session for the life of the repo, and their floor is roughly zero. The same paper's framework is a good read if you want to measure your own file rather than trust vibes.
Sanglard's own closing is the right calibration: this is not a magic bullet that lets you skip reading the code. He still verifies and iterates a lot. The difference is where his attention goes. Style and layering are now handled before he looks, so review time goes to architecture and design, which is the part only you can do.
Your checklist
- Copy Sanglard's original (linked above) or the Java adaptation, place it at repo root as
AGENTS.md, and symlinkCLAUDE.mdto it so both harnesses read one source of truth. - Move every mechanically checkable rule into Checkstyle and ArchUnit tests. Keep one line in
AGENTS.md: runmvn verifybefore claiming done. - Add the convergence rule if you ever let agents run unattended.
- One feature per session. Say "reload AGENTS.md" when quality drops.
- Update the file by asking the agent to update it. When you correct the same behavior twice, it becomes a rule, not a chat message.
If I were starting again, I would begin with the ArchUnit tests and the test-first rule and add the style lines only as they were actually needed. A file that grows from your real review comments beats a comprehensive one copied from the internet, mine included.
I write about Java, Spring Boot, and AI every week. Subscribe, it is free.
Have you written an AGENTS.md or CLAUDE.md for your Java repos? Which rule has earned its keep, and which did you delete? I would genuinely like to know what belongs in the next revision of mine.
Top comments (0)