Skip to content

---

title: Three clean code rules for agents, enforced by tools

slug: clean-code-rules

lang: en

published: 2026-10-31

words: 453

lines: 75

size: 2.6 KB

read: 3 min read

reel: In the age of agents, clean code matters more than ever

---

Three clean code rules for agents, enforced by tools

In the age of agents, clean code matters more than ever

You used to write the code yourself and remember why each decision was made. An agent starts every session from zero and copies whatever pattern it finds. A messy repo costs you tokens on every session, and its output gets messier.

So I keep three hard rules, and a machine checks each one. A rule nobody enforces is only a wish.

Rule 1: each part does its own job

An agent making a small change should only read a few files. In my backend the direction of every import is fixed, and code goes through layers in one direction:

output
api > schemas > services > selectors > models

import-linter fails the build if a layer reaches the wrong way. This is the real contract from my pyproject.toml:

toml
[[tool.importlinter.contracts]]
name = "inside each app: api > schemas > services > selectors > models"
type = "layers"
containers = ["apps.accounts", "apps.content"]
layers = ["(api)", "(schemas)", "(services)", "(selectors)", "(models)"]
bash
PYTHONPATH=src uv run lint-imports
output
Contracts: 5 kept, 0 broken.

Rule 2: comments are correct, every function has a docstring

The agent trusts what it reads. A wrong comment sends it the wrong way, so comments explain why, and every public function gets a Google style docstring:

python
def minutes(self, body_en: str, body_fa: str) -> int:
    """Return the reading time of the longer body.

    Args:
        body_en: English Markdown source.
        body_fa: Persian Markdown source.

    Returns:
        Whole minutes, at least 1.
    """

Ruff enforces it, along with everything else it can check:

toml
[tool.ruff.lint]
select = ["ALL"]

Rule 3: no dead code

When the agent sees an old login beside the current one, it has to guess which is real, and sometimes it guesses wrong. Removed code gets deleted, not commented out and not flagged off. Git remembers it. Ruff's ERA rules catch commented out code, which select = ["ALL"] already turns on.

Pay once

Keeping a repo this clean used to be expensive, so most teams lived with the mess. Now an agent does the cleanup. You pay once, and every later session reads less and gets more right.

Copy this into your CLAUDE.md

markdown
## Code rules
- Each module does one job. Respect the import direction: api > services > selectors > models.
- Every public function, class and module has a Google style docstring.
- Comments explain why, never what. Fix or delete a comment that is wrong.
- No dead code. Delete what is unused, including old versions. Git keeps the history.
- Before you finish, run the linters and the tests, and report their real output.

Run the checks in CI too, so no session can skip them.

en3 min read