This release is a pre-release and may not be stable for production use.
agentlint
Design-rule governance for agent projects. One tool, many projects: it discovers a project's skills, subagents, CLAUDE.md and AGENTS.md files, MCP configuration and Claude Code settings, checks each against its family of rules, adds the project's own rules, and reports under a policy that says which rules apply, at what level, and what is exempt for how long and why.
python -m agentlint friday # text report, exit 1 on errors
python -m agentlint friday --strict # warnings fail too (CI)
python -m agentlint friday --format html --out reports/friday.html --open
python -m agentlint friday --format github # GitHub Actions annotations
python -m agentlint friday --format json # for other tools
python -m agentlint friday --list-rules # the register for that project
python -m agentlint --list-rules # the built-in register, no project needed
Needs Python 3.11+ and pyyaml. pip install maat16-agentlint (PyPI; the bare name is taken and agent-lint too similar —
the import name and command are still agentlint) or pip install -e . from a checkout adds
the agentlint command. pip install --pre maat16-agentlint tracks main: every push there is
published as a dev pre-release by .github/workflows/publish.yml, and a vX.Y.Z tag
publishes a final version.
The rules, documented
Every rule is declared in code with its id, default level, summary, explanation and source, and the documents are generated from that register so they cannot drift:
- docs/: the common rules, one document per family.
projects/<name>/RULES.md: everything that runs for one project, including its own rules, with the levels its policy makes effective.
Regenerate after any rule or policy change:
python -m agentlint --list-rules --format md --split --out docs
python -m agentlint friday --list-rules --format md --out projects/friday/RULES.md
Families
Rules are DR-nnn design rules in packs, one per family, each with its number range:
| range | pack | what it covers | source |
|---|---|---|---|
| DR-000–009 | engine | the policy itself: expired and unused exemptions, crashed rules | agentlint |
| DR-010–099 | skills |
SKILL.md: the Agent Skills specification (hard rules, then recommendations) and Claude Code's extensions | agentskills.io, code.claude.com/docs/en/skills |
| DR-100–199 | claudemd |
CLAUDE.md, AGENTS.md, CLAUDE.local.md, .claude/rules: imports, depth, size, scope, credentials |
code.claude.com/docs/en/memory |
| DR-200–299 | mcp |
.mcp.json servers by transport type, expansions, approvals in settings, tool naming, credentials |
code.claude.com/docs/en/mcp |
| DR-300–399 | agents |
.claude/agents/*.md subagents: loading, names, tools, values, preloaded skills, hooks, budget |
code.claude.com/docs/en/sub-agents |
| DR-400–499 | settings |
.claude/settings*.json: strict JSON, permission rule syntax, modes that cannot apply, hooks, unknown keys |
code.claude.com/docs/en/settings, permissions, hooks; the published schema |
| DR-500–899 | reserved | ||
| DR-900–999 | projects/<name>/rules.py |
the project's own rules; one project pack per run | the project |
Discovery is automatic. A pack finds its own files anywhere under the project root,
skipping .git, node_modules, virtual environments and build trees. The report header
lists what was found. A policy may add or narrow the skill globs; it never has to list
files.
The model
Levels are error (fails the run), warn (prints; fails with --strict), info
(prints) and off (not run). A rule has a default; a policy may change it.
Exemptions name a rule, a path glob, a reason, an owner and an expiry date. A covered finding is still reported, marked EXEMPT with its reason, so nothing disappears. An expired exemption stops applying and is reported itself (DR-001). One that matches nothing is reported (DR-002). A rule that crashes is reported (DR-003), never skipped in silence.
Skips are rules that could not run, for example a project table that would not import. A skip is visible in every report and never counts as a pass.
Exit codes: 0 pass · 1 findings at a failing level · 2 the policy or a pack is broken (nothing was validated).
A project
projects/<name>/
policy.toml root, packs, level overrides, exemptions (skill globs only to add or narrow)
rules.py the project's DR-9xx rules (optional)
RULES.md the generated register for this project
... data the rules need (friday keeps its connector catalogue here)
[project]
name = "friday"
root = "../../../friday" # relative to this file
[rules]
packs = ["skills", "claudemd", "mcp", "agents", "settings", "rules.py"]
[rules.levels]
DR-024 = "off" # error | warn | info | off
[[exemptions]]
rule = "DR-013"
path = "friday/assets/*/.claude/skills/*/SKILL.md"
reason = "frontmatter moves under metadata in the next asset pass"
by = "suhail"
until = 2026-10-09 # a bare date
A policy is found by project name under projects/, or given as a path. A project with no
special rules needs only the [project] table; every built-in pack then runs.
Writing a rule
A rule is a generator that yields (path, message) pairs, paths relative to the project
root, or ctx.skip(reason) when it cannot run.
from agentlint.core import rule
@rule("DR-905", "error", "one-line summary", source="where the rule comes from")
def contracts(ctx):
"""Why the rule exists, in a sentence or two. This is the register's explanation."""
for s in ctx.skills: # discovered skills: dir, rel, text, meta, body, error
if ...:
yield s.rel, "what is wrong"
ctx carries root, policy, skills, files(*globs) for other project files, rel(path),
inventory for the report header, and a cache dict a pack can use to parse something once.
agentlint/packs/_shared.py has the helpers the built-in packs share: frontmatter and JSON
file loaders, the secret detector, hook and MCP server shape checks, tool and permission
rule syntax, the bundled settings schema. A new family is a new module under
agentlint/packs/ with its own range, named in a policy's packs.
Reports
text: what was found, one line per open finding, skips, exemptions grouped by entry, a summary line.json: inventory, findings, exemptions with state and match counts, the full register.github:::error/::warning/::noticeannotations for Actions, plus the summary.html: a self-contained page with the verdict, a filterable findings table, the exemptions table and the rules register. Write it with--out, open it with--open; the text report still prints so CI logs show the result.
CI
- run: pip install pyyaml -e ./agentlint -e ./friday
- run: python -m agentlint friday --strict --format github
- run: python -m agentlint friday --format html --out reports/friday.html
if: always()
- uses: actions/upload-artifact@v4
if: always()
with: { name: agentlint-friday, path: reports/friday.html }
Projects
friday: the desk. Its pack covers the desk layout, the connector scope, the code tables that mirror the assets, identical copies of shared skills and packaging.
Metadata
Release files for maat16-agentlint 0.1.1.dev3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| maat16_agentlint-0.1.1.dev3.tar.gz | 111.0 kB | With provenance | Details for maat16_agentlint-0.1.1.dev3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| maat16_agentlint-0.1.1.dev3-py3-none-any.whl | Python 3 | none | any | Details for maat16_agentlint-0.1.1.dev3-py3-none-any.whl |
Total release size: 202.0 kB
Release files / maat16_agentlint-0.1.1.dev3.tar.gz
| Download URL | maat16_agentlint-0.1.1.dev3.tar.gz |
|---|---|
| Size | 111.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f6728dad1350bcbde2ecedb969b02a736839e4bfdecf27a22205987acd17d06d
|
|
BLAKE2b-256 checksum How to use checksums |
d77a8a4c7dc200f0e9b10a079d26b7fb2ad63feb6e7a0fa5eaeb3c60abe8d7e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / maat16_agentlint-0.1.1.dev3-py3-none-any.whl
| Download URL | maat16_agentlint-0.1.1.dev3-py3-none-any.whl |
|---|---|
| Size | 91.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6577716c6968b5288d7d82d077c6f9776cfdd9e49a11a778d7d5fbfc2f41b155
|
|
BLAKE2b-256 checksum How to use checksums |
07d8074f646e6e1c19e6adb8d26b6570383c3437bc78d8f038ad9da840ef3ea1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logSecurity for maat16-agentlint 0.1.1.dev3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for maat16_agentlint-0.1.1.dev3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.