Skip to content

Architecture

Request and analysis layers

graph TD
    CLI["Generic axm CLI / MCP"] --> Tool["AXMTool"]
    Tool --> Auditor["audit_project"]
    Python["Python caller"] --> Auditor
    Auditor --> Framework["Framework detection and category registry"]
    Framework --> Rules["ProjectRule instances"]
    Rules --> Native["AST / radon / configuration readers"]
    Rules --> Process["Python or Node subprocess runner"]
    Rules --> Checks["CheckResult"]
    Checks --> Result["AuditResult"]
    Result --> Formatters["Human / agent / JSON formatters"]

The root Python surface returns typed audit models. get_rules_for_category returns a list of rule instances, not a result model. Rule registration happens when modules are imported via register_rule; the registry is indexed by category and framework. A class may expand to multiple instances. Use the category guide to inspect the current registry instead of relying on a fixed rule count.

Workspace dispatch and concurrency

The dispatcher recognizes packages/<member>/src/ and audits members concurrently with a bounded outer pool. Each member has its own context-local AST cache shared across that member's rule workers. Results are collected in input order and merged by rule ID using worst-of-member scores and failures. An exception at the rule boundary becomes a failed result; it does not abort the other rules.

Frameworks and workspaces describes the layout limits and the current override/quick-mode caveats.

External tools

Python subprocess checks use run_in_project where implemented. It resolves the nearest project environment and optionally requests runtime packages with uv. Type checking uses the project's own mypy. Its default timeout is 300 seconds; pytest/coverage uses 900 seconds. On timeout the shared runner kills the process group and returns exit 124, or re-raises under check=True.

Node subprocess rules use their own runner and project-local binaries or PATH tools. Expected finding return codes depend on the tool: TypeScript exit 2 can mean type errors rather than an environment failure.

Not every rule uses the same subprocess helper or failure classifier. The exact integration and external tool configuration affect which checks can run. See configuration.

Fix system

The audit path reports findings; audit_fix separately applies Python test-tree transformations using libcst and axm-anvil. Planning, file moves, fixture/helper management and reporting live in core/fix/. The orchestrator performs a bounded fixed-point loop, then helper extraction, formatting and a syntax gate in apply mode.

The pipeline reference explains why a one-pass preview, a restored test directory, and a successful syntax check each provide different evidence. None replaces test execution and caller-owned parity checks.

Models and output

AuditResult and CheckResult are Pydantic models with extra="forbid". Severity is an enum. Numeric scoring is separate from passed; the tool transport's success is separate again.

The audit tool uses format_agent for data and format_agent_text for compact text. Passing checks can be strings or structured entries; failures preserve available text, details and metadata. Strict format_json is a different API. See results and scoring.

Other entry points

audit_test wraps pytest and validates requested targets. doc_gate wraps a strict MkDocs build and classifies output. The audit_quality witness adapts category results to the witness contract. The MCP server's verify composes audit/governance tools separately; it is not an entry point shipped by this package.