cd /news/developer-tools/a-battle-tested-agents-md-for-higher… Β· home β€Ί topics β€Ί developer-tools β€Ί article
[ARTICLE Β· art-52879] src=gist.github.com β†— pub= topic=developer-tools verified=true sentiment=↑ positive

A battle-tested AGENTS.md for higher quality code output. Helps avoid "AI slop creep" by keeping your codebase lean and clean.

A developer shared a battle-tested AGENTS.md document designed to produce higher quality code output by preventing 'AI slop creep'. The document enforces principles such as defaulting to modular design, type-owned dispatch, and placing functionality where it generalizes to keep codebases lean and clean.

read6 min views1 publishedJul 9, 2026

This document exists to keep the codebase * minimal, elegant, and proper*.

Default to modular. When you design anything with more than one variant β€” or that will plausibly grow one β€” the first question is "what's the unit, and how does the rest of the code stay ignorant of which one it's looking at?" That mindset applies at every scale: from a small enum where one method per variant beats a branch at the call site, up to full subsystems with interfaces, registries, and per-variant files. The cost of designing modularly up front is almost always small; the cost of retrofitting after centralized branching has spread across the codebase is large. Hand-written dispatch should feel like an exception that needs justifying, not the default shape.

This is a stronger claim than the Engineering Principle's "build a proper system for it" β€” that one says don't hack; this one says the proper system is almost always one where new variants slot in without consumers being edited.

Module-specific code lives in the module. Module-generic infrastructure β€” registries, dispatchers, shared state, caches β€” is generic by name and by shape, never named after any single module that happens to use it today.

When adding a new item to a modular system (a new filter, tool, handler, etc.):

DO: Create a single unit (file/module) in the appropriate directory that contains everything about that variant β€” type, implementation, registration, constants, helpers.DO NOT: Add branches to a central dispatcher. Add entries to a hand-written list. Touch any file outside the module directory except whatever central manifest the build genuinely requires.

Prefer a mechanism where new variants are discovered (by a build step, a registry, reflection, or convention) rather than enumerated by hand. Generic infrastructure (the interface, the registration record, the registry) is named after the kind, not after the first variant that happened to exist.

The "default to modular" stance leads directly to the type-owned dispatch rule below: once a system is modular, the consumer must not re-introduce centralized branching by asking variants what they are.

Type-owned dispatch: Anything a type knows about itself β€” behavior, properties, capabilities, identity β€” lives on the type, behind a uniform interface. Consumers call methods; they never introspect, classify, or branch on which variant they got. The diagnostic question: would adding a new variant, or changing what an existing one knows about itself, force me to edit this code? If yes, the knowledge is misplaced. The violation has one recurring shape β€” a switch

/match

on a type tag, `if kind == X`

, an `is_foo(type)`

predicate, or any consumer-side helper that routes by type β€” code outside a type's own module asking questions the type should be answering itself. Replace it with a method, defaulted to the common case and overridden per variant, so new variants are purely additive.

Don't Repeat Yourself β€” and interpret this broadly. If two pieces of code aren't identical but follow a similar enough pattern that they could be generalized, they should be. This applies across modules, layers, and systems.

Place functionality where it generalizes. Before writing logic, ask: "where does this belong so that it works for all cases, not just this one?" If a behavior applies to any item of a kind, it belongs in that kind's generic hooks β€” not inside one specific item. If a behavior applies to any async operation, it belongs in the shared completion pipeline β€” not special-cased at one call site. Putting the right logic in the right architectural layer eliminates the need to repeat it, and prevents future features from having to rediscover where to plug in. A good signal you've placed something wrong: it only works for one workflow, or a second caller would have to copy-paste the same pattern.

Stop-sign phrases. If you find yourself writing "mirrors X", "bit-exact copy of X", "keep in sync with X", or "identical to X" in a comment, you are duplicating code. and consider why you're doing it. If it's not easily factorable into a shared feature, stop executing and raise the issue to the user.

State belongs to the thing it describes β€” not to a parent that manages it on its behalf. Don't let language or tooling constraints dictate the data model. If splitting state out of a structure makes some local concern easier but scatters a logical concept across multiple locations, find a different way to satisfy the constraint (helper methods, restructured access, narrower borrows/scopes) and keep the data model clean.

Before deciding on an approach, research how established projects in the same space handle it. Read the actual source β€” never rely on web searches, docs, blog posts, or LLM training data for architectural claims. If a reference project isn't available locally, clone it. Never claim "Project X does Y" without pointing to a specific file and function. When delegating research to a subagent, instruct it to clone and cite specific files and line numbers β€” reject any claim not backed by source.

We do not blindly copy prior art; we use it to inform our own decisions. Our implementation will differ in specifics, but core algorithms and architectural decisions should be informed by prior art, not invented from scratch.

When an idea, algorithm, snippet, or implementation comes from an external source β€” open source code, papers, blog posts, video tutorials, etc. β€” credit the source and author at the top of the file (or inline next to the borrowed fragment, if it's smaller than file-scope). Include the author's name or handle and a link to the original.

Every feature must have a test. Verify the feature works. The test exists; it passes. That's it.

Every bug must have a regression test β€” one that defends against that specific bug being reintroduced. "Regression" means "the bug we just fixed must not come back"; a test for a new feature is not a regression test, even if it follows the same pattern. Write it FIRST, confirm it FAILS against the unfixed code, then fix the bug and confirm it passes; if it doesn't fail without the fix, it doesn't count.

Every system must be implemented properly. No hacks, no hardcoding, no shortcuts. If we implement one of something, we build a proper system for it. It's okay to take a step back from the current task to do things right.

Every bug is a signal that something nearby is awkward or overcomplicated. Before patching, ask: "is this an elegant solution?" If the answer is no, the bug is telling you the code wants to be restructured β€” propose a refactor instead of layering a fix on top. The cleanest fix is often the one that makes the bug impossible to express, not the one that handles it.

Keep user-facing documentation in sync with the codebase. When you ship, remove, or rename a user-visible feature, update the corresponding docs (README, changelog, feature checklist) in the same change.

Speculative deletion. If code looks dead, delete it and see what happens. The compiler, type checker, and tests are the authoritative check, and version control restores it cheaply if you're wrong. Every file read is an opportunity to scan nearby code for vestigial slop. If you're not sure whether to keep an old snippet, err on the side of deleting, and let the user know what was deleted.

Run the project's formatter, linter, type checker, build, and test suite at commit time only β€” not during iterative debugging. Use the cheapest build/check command for mid-iteration sanity. All checks must pass before a change is considered done.

Never run git commit

β€” make the changes and leave staging and committing to the user.

── more in #developer-tools 4 stories Β· sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/a-battle-tested-agen…] indexed:0 read:6min 2026-07-09 Β· β€”