feat: add agents-md, the AGENTS.md validation tool - #3
Draft
tonyandrewmeyer wants to merge 7 commits into
Draft
Conversation
tonyandrewmeyer
force-pushed
the
feat/agents-md
branch
2 times, most recently
from
September 8, 2026 08:08
dba5617 to
9534eeb
Compare
Every Charm Tech repo carries an AGENTS.md, several agents read it, and a stale line in one is worse than a missing line: agents trust the file over the repo, so a wrong line produces confident errors where absence would have produced exploration. This package is the deterministic half of the scheme for keeping them honest -- three checks and one fix, plus the ten per-repo question batteries the battery check reads. The checks were written as part of the charm-tech-baseline audit tool and would otherwise ship with it. They are separated here because the two have different consumers and very different cadences: the baseline audit runs against a repo when someone asks it to, while this runs monthly across the estate and on every PR that touches an AGENTS.md. Splitting them means the monthly routine can pin a package that is only these checks, and a change to either does not force a re-review of the other. The batteries move with the checks rather than staying with the skill, so that the code that reads them and the data it reads ship together. common.py and tier.py are the same as their charm-tech-baseline counterparts. That duplication is deliberate for now: the alternative is a third package for 150 lines of exit codes and a JSON emitter, and a forced release order between the two. Worth revisiting if a third tool wants them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
Matches the root README and ai-failure-notifier's, which are both soft wrapped. GitHub wraps to the reader's window, so the hard wraps only made the paragraphs ragged there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
Four conventions settled on canonical#1 that apply here too, so that the second package in the repo does not arrive with a different set. * Apache licence header on every Python file, which none of these had. * Modules are private (`_cli`, `_common`, `_tier`, `_checks`, `_fixes`), so it stays hard to depend on tool internals from a CI hack later. * `__init__.py` is a docstring and nothing else -- the tool is a console script, not something to import -- with the entry point moved to `._cli`. * `[tool.ruff] extend = "../pyproject.toml"` rather than a comment asking people not to add a `[tool.ruff]` block, since extending means a setting added here overrides one key instead of the whole shared config. The modules inside `_checks` and `_fixes` keep their public-looking names: the runner derives check and fix identifiers from them, so `add_agents_md` is the name of the fix on the command line rather than an importable API. Also drops two comments explaining what a check used to do when it was a standalone script, which is the same leftover-from-one-file class that was picked up on canonical#1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
All three checks declared `product,canonical,personal`, so the tier gate never excluded anything -- it computed a value and then applied it to nothing. That is not an accident of this extraction: a well-maintained AGENTS.md is worth the same in a personal fork as in a product repo, which is not true of the requirements the tiers were built for (SBOM submission, TICS targets, security documentation). The baseline audit needs tiers; this does not have to inherit them. Removing it takes a network round trip out of every run: on a fork, tier detection shelled out to `gh repo view` to find the upstream, for a check that is meant to run in CI on every PR touching the file. Goes with it: `--tier=`, the `detect-tier` command, `parse_tier` and `tier_applies`, and the `tier`/`tier_source` fields in the report. Anything reading the JSON should not miss them, since they never varied by anything except the flag it passed in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
Follows the team Python style guide in canonical/charm-tech (style/python.md): a name prefixed with its module says where it came from. So `import pathlib` and `pathlib.Path`, `import types` and `types.ModuleType`, and `from .. import _common` with every use prefixed, rather than pulling the names in one at a time. `typing.Any` and `collections.abc.Iterator` stay as they are, under the guide's exception for typing names -- `Iterator` is only ever an annotation here, and the same verbosity argument applies to it. Worth noting for the review: `run` is a common enough word that prefixing its uses also caught it inside two regexes and a summary string, where `go run` and `make run` are side-effect keywords. Those are back as they were. The checks report the same findings against concierge and operator clones as they did before this change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
Nothing in a public repo should point at a path only some of us can read. * `seeded_from:` in all ten batteries named a file in that tree and nothing else, so the field goes rather than gets reworded. `seeded_on` and the AGENTS.md ref/SHA it was seeded against stay, since those are the provenance a reader can actually check. * The "Layer 1/2/3" numbering came from that document too, and without it the numbers say nothing. Each is now named for what it does, which mostly means saying `agents-md-content` where the text said Layer 1. * Two docstrings pointed at `lib/common.py` and `check.py`, which is the layout this code had two moves ago. Ten batteries still parse, entry counts unchanged, and the checks report the same findings against concierge and operator clones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XdsdR8QdcZY6GUJgd1Wt7c
All wording, no behaviour change. * The `agents-md` check docstring led with "best-of-class; agent-onboarding entry point", which labels the check rather than saying what it does. * `_common.py` explained that it is imported by every check and fix script and has no import side effects. Both are leftovers from when these were standalone scripts on a path, and neither is something a reader of this module needs to be told. * The two test module docstrings each carried a subordinate clause on the summary line; they are a summary and a body now. * The README paragraph explaining that there is no tier system was left over from the commit that removed it -- there is no absence to account for once the tiers were never here. * The opening paragraph pointed at "the scheme for doing that" without saying whose scheme, which was the last trace of the reference to the private planning tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YWerXBch3kzCs64fPXxPgU
tonyandrewmeyer
commented
Sep 10, 2026
tonyandrewmeyer
force-pushed
the
feat/agents-md
branch
from
September 10, 2026 01:06
9534eeb to
0bba17b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every Charm Tech repo carries an AGENTS.md, several agents read it, and a stale line in one is worse than a missing line: agents trust the file over the repo, so a wrong line produces confident errors where absence would have produced exploration. This package is the deterministic half of the scheme for keeping them honest: three checks and one fix, plus the ten per-repo questions the check reads.
The intention is that this runs monthly across the repos and on every PR that touches an AGENTS.md.
(#1 has landed, so this is rebased on it and the top-level files the two had in common are gone from here. What is left outside
agents-md/is the two lines that register the package: a row in the README table and an entry in the CI matrix.)