Skip to content

Commit 5169fce

Browse files
committed
docs: bound documentation and comment length in template AGENTS.md
Ports the added-fact rule from agentic-engineering-loop#434. The template enforces docstring presence (ruff D, numpy convention) but nothing bounded their length, so agents in a generated project produced Parameters/Returns blocks that restate annotations and docstrings that only grow. The new Documentation and Comment Style section states the rule: past the summary line, a line must carry a fact the code cannot. Also assert AGENTS.md and CLAUDE.md land in the generated project, and that AGENTS.md has no unresolved Jinja placeholders.
1 parent 3268278 commit 5169fce

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

‎template/AGENTS.md.jinja‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,40 @@ those blocks once you start modelling your own domain.
7070
{%- else %}
7171
- `make lint` runs ruff and the `ty` type checker.
7272
{%- endif %}
73+
74+
## Documentation and Comment Style
75+
76+
Brevity is not tidiness — it is what gets the text read. A docstring, comment,
77+
or page nobody reads still has to be maintained, so it is worse than none.
78+
79+
Docstring *presence* is enforced by ruff's `D` rules (numpy convention) in
80+
`pyproject.toml`. This section bounds their *length*.
81+
82+
The unit of judgement is the *added fact*: after the summary line, every line
83+
must tell the reader something they cannot get from the name, the signature,
84+
the type hints, or the code itself.
85+
86+
Earns more than a summary line:
87+
88+
- a contract the signature doesn't show — preconditions, invariants, what it
89+
raises
90+
- units, bounds, or formats a type can't carry (`timeout: float` — seconds or
91+
milliseconds?)
92+
- caller-visible behaviour that would surprise — mutation, ordering,
93+
idempotency, blocking, retries, cost (a network round-trip, an LLM call)
94+
- a pointer to the *why* when it isn't obvious (link the issue or ADR, don't
95+
restate it)
96+
97+
Does not:
98+
99+
- restating the signature, or a numpy `Parameters`/`Returns` section where the
100+
name and type already say it
101+
- narrating the implementation step by step — that's the code
102+
- history ("previously…", "refactored to…") — that's git
103+
- examples for a function whose use is obvious from its name
104+
105+
The same rule governs prose: the README covers what a reader needs to install,
106+
run, and maintain the project; implementation detail belongs in the code.
107+
Prefer a list, table, or short code example over paragraphs. When editing an
108+
existing docstring, comment, or page, it must not get longer unless behaviour
109+
was added.

‎tests/test_template.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ def test_template_renders(project):
6363
assert (project.path / "src" / "test_project" / "__init__.py").is_file()
6464
assert (project.path / "src" / "test_project" / "main.py").is_file()
6565
assert (project.path / "tests" / "test_test_project.py").is_file()
66+
assert (project.path / "AGENTS.md").is_file()
67+
assert (project.path / "CLAUDE.md").is_file()
68+
# AGENTS.md is rendered from a .jinja source, so placeholders must resolve.
69+
assert "{{" not in (project.path / "AGENTS.md").read_text(encoding="utf-8")
6670

6771
domain = project.path / "src" / "test_project" / "domain"
6872
example_test = project.path / "tests" / "test_example_notes.py"

0 commit comments

Comments
 (0)