aigx-lint
A tiny, zero-dependency (Python 3.8+ stdlib) validator and resolver for AIGX genomes. It exists to kill the two most common objections to a centralized context format - "it rots" and "it won't scale" - by making both mechanically false.
Why
- It can't rot silently.
aigx-lintchecks the genome against the actual repository: every<file path>must still exist on disk, and every<check>id must resolve to a real<rule>. Run it in CI or a pre-commit hook and a moved/renamed file fails the build until its entry is fixed - the same discipline teams already use forCODEOWNERSandtsconfigpath maps. - It scales by resolution, not ingestion.
--resolve PATHreturns just one file's entry, so an agent's context cost is O(1) per edited file, independent of index size. A 50,000-entry index is one lookup. - It understands hierarchical genomes. Every
.aigx/directory under the root is discovered; eachfiles.aigxindexes its own subtree (see SPEC §8).
Usage
# Validate the genome(s) under the current repo. Exits non-zero on errors (CI-friendly).
python aigx_lint.py --root .
# Print just one file's boundary entry - constant-cost lookup an agent/MCP can call.
python aigx_lint.py --resolve src/features/meetings/bookMeeting.ts --root .
# Machine-readable output for MCP servers, editor extensions, and agent wrappers.
python aigx_lint.py --resolve src/features/meetings/bookMeeting.ts --root . --format json
# Summary: genomes, rules, entries, and the all-important forbid scarcity.
python aigx_lint.py --stats --root .
--resolve returns exit code 0 when the target file exists even if the genome has no matching
<file> entry; that is an informational "no boundary indexed yet" result, not a tool failure. It returns
exit code 2 when the target path itself does not exist.
What validation catches
| Check | Why it matters |
|---|---|
<file path> exists on disk |
catches renamed/moved/deleted files → the genome can't go stale unnoticed |
every <check> id resolves to a <rule> |
catches dangling references when a rule is renamed/removed |
duplicate <file> entries (warning) |
catches copy-paste drift across shards |
JSON shape
JSON output is intentionally small and stable so MCP bridges can inject AIGX context without scraping XML:
{
"found": true,
"path": "src/features/meetings/bookMeeting.ts",
"domain": "meetings",
"role": "Book a meeting (validate slot + contact)",
"forbid": { "priority": "CRIT", "text": "NEVER import internal suppliers modules" },
"gotcha": { "priority": null, "text": "Use the public suppliers API for contact email" },
"checks": ["ARCH-no-deep-imports", "DATA-integer-cents"],
"block": "<file path=\"...\">...</file>"
}
When there is no indexed boundary for an existing file, found is false and exists is true.
Try it on
examples/sourcing-app/:--statsand--resolvework directly;--validatewill (correctly!) report thesrc/**paths as missing, because that example ships only the genome, not the application source - which is exactly the "moved/missing file" signal the linter is built to catch. Run it against a real checkout to see it pass clean.
CI examples
GitHub Actions:
name: aigx
on: [push, pull_request]
jobs:
lint-genome:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.x" }
- run: python tools/aigx-lint/aigx_lint.py --root .
GitLab CI:
aigx-lint:
image: python:3.12-slim
script:
- python tools/aigx-lint/aigx_lint.py --root .
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
Bitbucket Pipelines:
pipelines:
default:
- step:
name: Lint AIGX genome
image: python:3.12-slim
script:
- python tools/aigx-lint/aigx_lint.py --root .
Pre-commit hook (catches issues before they reach CI):
# Install once: copy to .git/hooks/pre-commit and make it executable
#!/usr/bin/env bash
set -e
python tools/aigx-lint/aigx_lint.py --root .
chmod +x .git/hooks/pre-commit
Or use pre-commit framework with a local hook:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: aigx-lint
name: Lint AIGX genome
entry: python tools/aigx-lint/aigx_lint.py --root .
language: python
pass_filenames: false
always_run: true
That's the whole answer to "decoupled docs rot": don't decouple and walk away - decouple and lint.
Release files for aigx 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aigx-1.2.0.tar.gz | 23.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aigx-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.3 kB
Release files / aigx-1.2.0.tar.gz
| Download URL | aigx-1.2.0.tar.gz |
|---|---|
| Size | 23.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
56328d44abd05745e060134590fed463bad0bd29759597d9df94b1c03275cf01
|
|
BLAKE2b-256 checksum How to use checksums |
88dffe35297e31ea1e7f73f8b610e115429992b678b5c56144553836ca21d68f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / aigx-1.2.0-py3-none-any.whl
| Download URL | aigx-1.2.0-py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f7c7f825730ccb16cd7ff54c0b6086f7bd535e265f2068be44f9d23e6ec23fb
|
|
BLAKE2b-256 checksum How to use checksums |
09589fbdbe85f31a72f2f4da189b0e31ac85069accd3e4d9c409bdaf0d73ed55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|