How the modern-python repos are set up for coding agents
modern-python is about thirty repositories, maintained by one person, with coding agents working in every one of them. This page describes the setup that makes that workable, using the same four parts as the agent-ready backend offer. Everything here is public and linked, so you can check it.
Context the agent can use
Every repo has an AGENTS.md at the root. It holds what an agent can't learn by reading the code:
the commands, where each concern lives, and the rules that leave no trace in the code that follows
them. lite-bootstrap's
is a typical one. It explains why every link in README.md must be absolute (the README is also
the PyPI description, and PyPI doesn't rewrite relative links), and it lists four code style rules,
each with the reason behind it.
Most repos also carry a CONTEXT.md, a glossary limited to terms with a synonym to reject or a
meaning subtle enough that code and docs have to agree on it. Each entry names the words to avoid.
In lite-bootstrap's, an
instrument being configured and a bootstrapper being ready are separate terms, and the agent is
told to use them exactly.
Decisions go into architecture decision records under docs/adr/, 88 of them across the repos. A
short domain doc
tells the agent to read the ADRs for the area it is changing, and to say so when its change
contradicts one instead of quietly overriding it. Two more docs in the same folder describe the
issue tracker and the triage labels, so an agent can pick up and file GitHub issues through gh.
Above the repos sits the standard: numbered requirements, each with a stable ID and usually a Why line. An agent can cite CI9 in a pull request the same way a person would.
Checks for agent-written code
An agent's change goes through the same checks as anyone's, and the commands are identical locally and in CI:
- The
justfilehas a fixed set of recipes (JF1).just lintrewrites files, andjust lint-ciruns the same checks read-only. - ruff, ty and eof-fixer, required by the standard (TL2), with a 100% line
coverage gate (TS2). A
pragma: no covershould carry its reason on the same line (TS6). - The
floorsjob installs every dependency at its lowest declared version and runs the suite (CI10), which catches code that only works on the latest release. - A links job fails on any relative link or file path the diff broke (CI7), and
docs sites build with
mkdocs build --strict(CI8). - A shared check fails when a file cites an ADR that doesn't exist (CI9).
Some rules are tests. The org repo's
tests/test_site.py
asserts that the site's project lists match the brand manifest, and each test's docstring opens
with INVARIANT: and explains what breaks without it. An agent that removes the check has to argue
with the reason in front of it.
Signals from outside the diff
Libraries don't have a production environment, so this part is thin here. The closest thing is a daily scheduled run of each published repo's checks (CI2). When a dependency release or a new Python breaks a repo, a shared workflow opens or updates an issue linking the failing run, and an agent can pick that issue up like any other.
Telemetry
The same applies to telemetry: a library has none of its own. For services, the org's answer is
lite-bootstrap, which wires OpenTelemetry,
Prometheus, Sentry and structlog into FastAPI, Litestar or FastStream. In a client's service, this
part and the one above carry more weight than they do here.
What we learned
Copies drift, even byte-identical ones. Twenty-five copies of the ADR citation test drifted within a month of being written, so the repos now fetch one shared file from the org repo, unpinned (CI9). Per-repo scripts that reported scheduled failures drifted the same way, and several named a dependency their repo didn't have. They were replaced by one shared workflow (CI2).
Not everything should be shared. A single CI workflow for all repos was built and rejected
(#95): reusable workflow inputs are plain
strings, so service containers and environment maps had to be flattened into them. Each repo keeps
its own _checks.yml (CI3), and a change to the jobs is a sweep across repos.
Write down only what the code doesn't show. Agents read code well. What they miss is the reason a
link must be absolute, why a type checker's warning is noise, or which word the project has already
rejected, and that is what the AGENTS.md and CONTEXT.md files hold.
If you'd like the same setup in your own codebase, see services.