My agent.md to improve LLM-assisted code quality
fabiensanglard.net
fabiensanglard.net
Then this one really is a pattern that creates a lot of churn:
- Add a small, to the point, comment to explain what the block does and why. Use examples when possible. Propose ASCII drawings to explain complete systems.
The what _is_ the code.
Maybe I am some god tier code reader (i am not) but i dont think i have ever found a comment in code to be useful in my day job. That isnt true, i once came across
// submit to the dark lord
Above the function that sent a payment to PayPal for processing. It made me laugh so I let it be.
“”” After you give up on trying to refactor this code, increment the following line accordingly. HOURS_WASTED_HERE=26 “””
It’s almost the “we built a robot who loves to play Sonatas and gave it no hands” type of thing.
For the latter I'll often include an example of a comment it wrote, along with my own rephrasing, and tell it that "future readers will understand code context; good naming is the best documentation". This works alright if I include in the actual prompt, but annoyingly it often doesn't in CLAUDE.md or memory.
With the mechanical routes, we get checks, failures, and so much more. A bit wild to me.
Make an agent operate within defined constraints and yell at it when it doesn’t.
Of course, ensuring compilation or other checks can verify some code, which it can’t do for comments. But comments still serve the same purpose as human comments.
The problem with comments is that LLMs tend to copy their verbose chat output format and insert session/prompt specific details. It makes me think that LLMs aren’t constrained in their comment output the same way they are with their code output
Please take the following as expressed with genuine curiosity: Do you not use an editor with syntax highlighting and collapsible comments?
At least on JetBrains you can configure the editor to collapse all comments on open and to have the comments displayed in a low-contrast color. This way, LLMs add a bunch of comments, but it doesn't affect your actual experience in trying to read the code. If you encounter code that seems inexplicable, then and only then would you expand the comment to see if that helps you understand.
The next developer doing a review will see it. The next agent iteration will see it.
If the comment is wrong (even slightly) or redundant, that will help noone.
Comments should be written only when there is (hidden) complexity or external context strictly required. Otherwise it is just easier to read the code. Comments then signal one of two things: a) the following code is really complex and I need to tread carefully, or b) this code is complicated, and could benefit from a refactor.
In regards to agentic coding, all these comments are extra contents, driving down quality while increasing cost. Agents also tend to be inconsistent about updating comments, I've had cases repeatedly where a comment did not match the code, at which point it is just a documentation liability.
I just added Sanglard's rules to my ~/.claude/CLAUDE.md file, did another code review, and found some LLM-generated comments were really hard to understand. I think they're due to invented metaphors and flowery language instead of using standard terms, so I've added this:
- Comments must be literal. Don't invent figurative language for what a plain technical term already says — write "rows still reference it," not "rows still wear it."
Improving LLM code generation is an iterative process. I'm glad people share their efforts to improve it.
LLMs are very bad at ASCII drawings.
https://medium.com/data-science/why-llms-suck-at-ascii-art-a...
> Write in-code comments that describe _why_ code or a class does what it does, but not _what_ it does. The "what" should be self-evident.
Even the why sometimes shouldn’t be a comment, unless it’s very immediate to the code itself. What’s often more necessary is a high level overview of the design of the solution, because that’s what drives the design of the code and link disparate section. Especially the glossary , which you let you understand the name of the symbols (variables, struct. functions,…) used in the code.
It’s like learning the culture associated to a foreign language instead of trying to translate each single word with a dictionary.
They're fast and deterministic and I run them in git pre-commit.
Isnt that too late? I would want the agent to stumble into this as early as possible in the agentic loop, eg at the same time as compiler.
But that's a pretty good idea, wonder if there is a way...
Now you might say, don't write huge functions. Sure I agree, but most codebase or teams are not super disciplined enough. So comments are a compromise.
Recently I asked GPT to port a browser game to Rust. It voluntered this gem:
draw_image_with_html_image_element_and_sw_and_sh_and_dx_and_dy_and_dw_and_dh(...)
I thought it was smoking some good stuff, but it turned out, that is actually the name of the function!
https://docs.rs/web-sys/latest/web_sys/struct.CanvasRenderin...
A. Success The intended capability works in the real path and the real motivating case materially improves.
B. Meaningful progression The capability is not complete, but one genuine blocker is removed and the next blocker is isolated with evidence.
C. Honest stop Further work would require overbroad scope expansion, excessive debt, brittle patching, or tangled logic. Stop and report the reason with concrete evidence.
Do not continue producing patches once the work stops converging.
Do not confuse activity with progress. A failed attempt is only acceptable if it leaves behind a narrower problem, stronger evidence, or a justified stop.
Any partial work must leave the codebase in a cleaner, more legible, and more diagnosable state than before. ----
A lot of the article's AGENTS.md just feel like telling the LLM agents either something they already know (for example, most of the time they know to use exhaustive switch/match statements instead of "arrow anti-pattern") or seems actively harmful ("keep function names short" seems arbitrary and may cause the LLMs to write weird abbreviations for functions that are harder to read and review.
What's the difference between a "genuine blocker" and a "blocker"? Why is the next blocker not genuine? Does it become genuine only after isolation?
**Always use ASD-STE100 Simplified Technical English
Disclaimer: I saw this listed in some other HN post that I can' locate right away.
I have been using it for a few weeks, and it significantly improves the quality of the docstrings and code comments, as well as the readability of spec docs.
I have also added a few key bullet points to my AGENTS.md and have found the results to be very effective and generating plans and code that looks like something I would have written:
-----------
## planning, design and spec docs
- the highest design goal is simplicity -- in our systems and our mental model -- even if if means edge cases are unaddressed and could potentially fail
- please practice "ya ain't gunna need it" (YAGNI) do not add unnecessary guardrails
- do not plan to add caching, many layers of unnecessary abstraction or other premature optimizations
- look for places where adding or clarifying an invariant would simplify the code or the overall system
please specifically try to avoid:
- redundant calculations or duplicated work
- duplicated conditionals or state-machine logic
- storing state that can be derived from other state, which could drift and become out of sync over time
- leaky abstractions across layers of the application
- multi-line comments explaining a variable name or a single statement. well chosen names and design should makes these unnecessary, as the code is self-documenting- Prefer documentation as code
- Comment why, not what
- Document public APIs
- Readability is paramount
That usually gets me 80% there; rest is covered by the linter.
I'm mostly just missing it explaining previous state too much, especially when making edits to plans, but I have not found good wording for that yet.
When you say "don't do x" you are just pre-seeding the model with "x" and the prohibition mitigates that some, but not as much as never having put "x" in the context in the first place.
"Do Y, for these reasons" can be shaped to achieve what you mean by "Don't do X"
"Don't do X" leads to "Wait, I need to make sure I didn't X" and "Let's look up X to make sure I don't do that." And each time the odds of X happening keeps going up, not down.
Personally, I tend to do 3 passes, where I ask the agent to write, and self review; that's been enough to get things functional enough that I don't need to read the code.
To me when I code by hand, I never use {} after an if statement if it's one-line, it's just faster, look cleaner to me.
And what are you going to do with all that time you saved by not pressing a single key?
## Voice
Rule #1: No AIisms
Avoid the stock phrases and rhetorical tics that mark AI prose. Say the thing plainly instead. Be concise and direct.
*Banned phrases* — never use these, or close variants:
- "Honest" or "honestly"
- "Exactly" or "exact, unless referencing a specific quantity or measurement
- "You're absolutely right" / "You're right to push back" / "Great question"
- "load-bearing", "full stop", "worth stating plainly", "worth noting"
- "the honest answer", "to be clear", "let me be direct"
- "it's not just X, it's Y" — and every cousin: "not X but Y", "X is not Y; it is Z", "this isn't X — it's Y"
- "this matters because", "that reduction is useful, because", "here's the thing", "and that's the trap"
- "in other words", "put differently", "better posed:", "the deeper point is"
- "delve", "leverage", "harness", "unlock", "tapestry", "realm", "seamless", "robust", "holistic", "paradigm", "cutting-edge", "game-changer", "transformative", "elevate", "empower", "streamline", "landscape", "ecosystem" (unless literally software packaging)
- "genuinely", "structurally", "fundamentally", "quietly", "meaningfully" as depth-manufacturing adverbs
- "Ultimately," / "At the end of the day," as a closing summary
- "serves as", "stands as", "represents", "marks a" where "is" works
- "say the word"
*Banned moves:*
- The aphoristic closer. Don't end on a line engineered to sound quotable.
- The suspense hook — "the cleanest way to think about this is this:"
- Anticipate-and-rebut — raising an objection only to knock it down.
- Meta-signposting — "Three caveats belong up front", "below I'll explain".
- Reflexive hedging stacks: "almost", "tends to", "roughly", "largely", "with few exceptions".
- Litotes as confidence: "not difficult", "not optional", "no small thing".
- AI-humility asides about being a language model.
- Self-ranking your own points: "most importantly", "the key insight here".
- Em dash overuse. One per paragraph at most; a comma usually works.
- Colon-reveals and dramatic mid-sentence pauses where "and" or "but" is the real conjunction.
- Fragment rhythm. Not every third sentence. Like this.
- Uniform structure — every paragraph three sentences, every sentence the same length. Vary it.
- Mirrored clauses: "X does A; Y does B" balanced for symmetry alone.
- Validate-then-precise: "That's correct, and we can make it precise."
Vary the openers. Don't answer three messages in a row with the same shape.