Skip to content

Architecture

axm-echo is a flat set of single-responsibility modules — no core/ / adapters/ split, no hexagonal layering. The two axm.tools entry points (echo_code, echo_check) orchestrate a shared corpus → embed → compare pipeline; everything else is a leaf the tools compose.

graph TD
    subgraph "Tools (axm.tools entry points)"
        EchoCode["EchoCodeTool · echo_code"]
        EchoCheck["EchoCheckTool · echo_check"]
    end

    subgraph "Pipeline"
        Corpus["corpus · extract_package / extract_monorepo"]
        Embedding["embedding · embed / neighbors (tfidf | st)"]
        Cluster["cluster · cross_pairs / split_pairs / cluster_pairs"]
        Waiver["waiver · cluster_hash / acknowledged"]
    end

    subgraph "Leaves"
        Scope["scope · load_scope (~/axm/echo.toml)"]
        Structural["structural · jaccard_similarity (stdlib, no torch)"]
    end

    EchoCode --> Corpus
    EchoCode --> Embedding
    EchoCode --> Cluster
    EchoCode --> Waiver
    EchoCheck --> Corpus
    EchoCheck --> Embedding
    Corpus --> Scope
    Corpus -->|axm-ast| Embedding

Modules

Module Role
tools The echo_code / echo_check AXMTools (MCP + CLI + DAG node). They run the pipeline and shape the ToolResult.
corpus Extract public symbols from a package (extract_package) or the whole scope (extract_monorepo) via axm-ast; each Symbol carries an embed_text.
embedding The two backends behind embed()tfidf (scikit-learn, pure CPU) and st (MiniLM, neural). neighbors() does exact cosine top-k.
cluster Cross-package candidate pairs (cross_pairs), the v7 anti-signal split (split_pairs: dupes / parallel-API / boilerplate), and union-find clustering.
waiver The acknowledged-cluster mechanism: a stable cluster_hash and the [[tool.axm-echo.acknowledged]] waiver lifecycle (mark / stale).
scope Resolve the workspace roots to scan from ~/axm/echo.toml, degrading to the current directory when absent.
structural 100%-structural similarity over ast.FunctionDef bodies (statement_set + jaccard_similarity); pure stdlib, never loads torch. The primitive duplicate_tests reuses.

Design decisions

Decision Rationale
Neural by default (st/MiniLM) Docstring similarity wants semantics; torch + sentence-transformers ship in the base install.
tfidf backend kept A pure-CPU opt-out for callers that must avoid loading torch — embed(texts, backend="tfidf") and --backend tfidf.
Lazy torch import torch is imported only inside the st backend, so the tfidf path stays light at runtime even though torch is installed.
Flat modules, no hexagonal split Each module is one concern with a small public surface; the tools compose them. No abstract ports to swap.
Exact cosine (no ANN) Corpora are monorepo-sized; brute-force matmul is exact and fast enough, with no index to maintain.