Metadata-Version: 2.4
Name: aigx
Version: 1.2.0
Summary: Reference validator + resolver for AIGX (AI Genome Exchange) — the open context format for AI coding agents. Zero dependencies.
Author-email: Grégory Parisotto <gregory@feex.it>
License: MIT
Project-URL: Homepage, https://github.com/Lolner95/AIGX
Project-URL: Specification, https://github.com/Lolner95/AIGX/blob/main/standard/AIGX-1.1.md
Project-URL: Source, https://github.com/Lolner95/AIGX
Project-URL: Issues, https://github.com/Lolner95/AIGX/issues
Keywords: aigx,ai-genome-exchange,ai,agents,context,lint,validator,llm
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# 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-lint` checks 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 for `CODEOWNERS` and `tsconfig` path maps.
- **It scales by resolution, not ingestion.** `--resolve PATH` returns 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; each
  `files.aigx` indexes its own subtree (see [SPEC §8](../../SPEC.md#8-scaling-to-large-repositories--monorepos)).

## Usage

```bash
# 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:

```json
{
  "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/`](../../examples/sourcing-app/): `--stats` and `--resolve` work
> directly; `--validate` will (correctly!) report the `src/**` 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:**

```yaml
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:**

```yaml
aigx-lint:
  image: python:3.12-slim
  script:
    - python tools/aigx-lint/aigx_lint.py --root .
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
```

**Bitbucket Pipelines:**

```yaml
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):

```bash
# 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 .
```

```bash
chmod +x .git/hooks/pre-commit
```

Or use [`pre-commit`](https://pre-commit.com) framework with a local hook:

```yaml
# .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*.
