Skip to content

Architecture

Overview

axm is a thin autodiscovery CLI wrapper that delegates all functionality to installed AXM ecosystem packages. It contains zero business logic.

graph TD
    AXM["axm CLI"] -->|"discovers via<br>entry_points"| INIT["axm-init"]
    AXM -->|"discovers"| AUDIT["axm-audit"]
    AXM -->|"discovers"| BIB["axm-bib"]

    subgraph "Base Types"
        TBase["tools.base<br>AXMTool / ToolResult"]
        HBase["hooks.base<br>HookAction / HookResult"]
    end

    GIT["axm-git"] -.->|"imports"| HBase
    TICKET["axm-ticket"] -.->|"imports"| HBase
    MCP["axm-mcp"] -.->|"imports"| TBase

    style AXM fill:#4CAF50,color:#fff
    style INIT fill:#2196F3,color:#fff
    style AUDIT fill:#2196F3,color:#fff
    style BIB fill:#2196F3,color:#fff
    style TBase fill:#FF9800,color:#fff
    style HBase fill:#FF9800,color:#fff

Autodiscovery Pattern

At startup, axm scans the axm.commands entry-point group:

Python
for ep in importlib.metadata.entry_points(group="axm.commands"):
    command_fn = ep.load()
    app.command(command_fn, name=ep.name)

Each AXM package declares its commands in pyproject.toml:

TOML
[project.entry-points."axm.commands"]
init_scaffold = "axm_init.cli:scaffold"
init_check    = "axm_init.cli:check"

This is the same pattern used by axm-mcp for tool discovery (axm.tools group).

Design Decisions

Decision Rationale
Entry-point autodiscovery No hard dependencies on ecosystem packages
Optional deps (axm[init]) Users install only what they need
cyclopts for CLI Same framework as other AXM CLIs
src/ layout PEP 621 best practice, no import conflicts
Zero business logic All functionality lives in dedicated packages
{domain}_{action} naming One name for CLI and MCP — no mental translation
AXMTool/ToolResult in axm Shared interface, no private dependency needed; text field carries pre-rendered output
HookAction/HookResult in axm Hooks contract without pulling axm-engine deps
Core contracts re-exported from the axm root The seven contracts (AXMTool, ToolResult, HookAction, HookResult, WitnessResult, ValidationFeedback, WitnessRule) are re-exported from axm/__init__.py as a pure façade — types stay defined in their submodules. Root re-export is the stable import boundary for a Core SDK; future renames are deliberately breaking
agent_hint on AXMTool LLM-optimized one-liner propagates to MCP tool descriptions — richer than docstrings, cheaper than system prompts