Skip to content

alexei-led/archfit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

504 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

archfit

CI Release Version GHCR Go Reference Go Report Card License

Does this change keep the architecture healthy? archfit answers — with a decision, not a number.

archfit is a one-command architecture-fitness CLI. It reads how your code is actually wired (from language analyzers like go list, dependency-cruiser, ast-grep, grimp), checks it against the architecture you declared in .archfit.yaml, and gives you a clear verdict: a decision, a CI gate, a banded scorecard, and — when an AI agent breaks a boundary — a structured repair task.

Built for AI agent and CI workflows: deterministic output, pipe-friendly, leads with what to do.

$ archfit

ARCHFIT RESULT

Decision   ACCEPTABLE WITH WATCH ITEMS
Gate       PASS  ·  0 blocking
Warnings   55 advisory
Score      43 / 100  mixed

Acceptable with watch items. Monitor flagged areas.

No blockers. Use this run for architecture-improvement planning,
not to stop development.

RECOMMENDATIONS

  MUST FIX
    none
  SHOULD FIX
    · bc/imbalanced_coupling — high fan-in into session state
  WATCH
    · lazy_cycle — lazy import SCC

WHY THE SCORE IS LOW

  coupling_balance  43/100  [mixed]
    304 warning edges, mostly functional + high volatility.

WHAT WOULD IMPROVE THE SCORE

  coupling_balance
    Reduce high-fan-in functional edges across module boundaries or introduce stable contracts.

TARGETS
  Current     43  mixed
  Near-term   61-80  serviceable
  Main goal   keep blocking findings at 0

Run it bare for a human-readable review; add --gate in CI for exit codes; add --json to pipe it anywhere. Progress streams to stderr, so archfit --json | jq stays clean.

Why

AI agents are great at local edits and bad at holding the whole system design in context. An agent can make a change that passes every test while it quietly imports across a forbidden boundary, bypasses a module's public API, shortcuts between layers, or grows a dependency cycle. Each one looks harmless; together they become the architecture, and every later fix costs more human context, more tokens, and more retries.

archfit puts an architecture-fitness check in that loop:

flowchart LR
    A[Agent edits files] --> C["archfit analyze --gate"]
    C -->|clean| P([PR opened])
    C -->|violation + agent_tasks| R[Agent applies the repair order]
    R --> C
    classDef ok fill:#d3f9d8,stroke:#2f9e44,color:#000;
    classDef gate fill:#ffe3e3,stroke:#e03131,color:#000;
    class P ok;
    class C gate;
Loading

A failed gate isn't a vague log line — it's a repair order the agent can act on:

{
  "rule_id": "no_internal_access",
  "goal": "Replace the internal-API access from pkg/a/a.go to pkg/b/internal/impl.go with b's public API.",
  "constraints": [
    "Use only the public API of module b",
    "public surface of \"b\": [pkg/b/api/**]"
  ],
  "files": ["pkg/a/a.go", "pkg/b/internal/impl.go"],
  "validation": ["archfit analyze --gate -c .archfit.yaml --full"]
}

Goal, constraints, the files to touch, and the command that proves the fix.

Quick start

# install (or use the Docker image with all analyzers bundled: ghcr.io/alexei-led/archfit)
go install github.com/alexei-led/archfit/cmd/archfit@latest

archfit doctor                      # which analyzers are available
archfit config init --root .        # generate a starter .archfit.yaml
archfit                             # human review: the decision report above
archfit --gate --full               # CI gate: exit 0 clean / 1 violation / 2 warn / 3 error

Accept current known debt as a baseline so it doesn't mask new findings:

archfit baseline --full

Starter configs for common project shapes live in examples/. Full setup — Docker, CI, optional analyzers, platform packages — is in the guide.

What you get

  • One command, many outputs. archfit analyze → terminal report (default), --json, --sarif, --markdown, or --format scorecard. --gate turns on CI exit codes; without it the run is report-only.
  • A decision, not just a scoreHEALTHY / ACCEPTABLE WITH WATCH ITEMS / NEEDS ATTENTION / FAIL, with blocking-vs-advisory split, categorized recommendations, and evidence for why the score is low / what would improve it.
  • Deterministic gates for forbidden dependencies, public-API boundaries, layer direction, cycles, and configured thresholds. Same input → byte-identical JSON, safe for CI.
  • agent_tasks repair blocks so an AI agent gets the fix, not just the error.
  • A banded coupling_balance scorecard built on Balanced Coupling (integration strength × distance × volatility), reported as a 0–100 score — optionally gates the build via coupling.gate (band floor / max score drop).
  • Visible evidence quality — SCIP strength overlays, Rust deep-analysis coverage, distance-basis context, and dynamic connascence signals are reported separately so missing or report-only evidence is not mistaken for score input.
  • Honest coverage — a missing analyzer degrades the affected metric to n/a with the install step, never a false green.
  • Content-addressed fact cache — warm runs skip unchanged extractor subprocesses (typically 3–5× faster gates), byte-identical to a cold run; --no-cache forces a clean control run (details).
  • Off-gate LLM enrichment (analyze --llm, config enrich labels/abstained, config init --llm, config update --llm) that may only draft labels, propose review material, explain, and prioritize collected evidence — it never decides the gate.
  • Multi-language — Go, TypeScript/JavaScript, Python, Rust (details).

How it works

archfit separates facts, gates, and narration. Language adapters collect dependency facts; a deterministic, LLM-free core classifies them, runs the gates, computes metrics, and synthesizes the decision; optional LLM features sit strictly off to the side.

flowchart TB
    tools["External analyzers<br/>go list · dependency-cruiser · ast-grep · grimp"]
    CFG[".archfit.yaml"]
    tools -->|dependency facts| core
    CFG --> core
    subgraph core["archfit core — deterministic, no LLM"]
        direction LR
        CL[classify] --> RU[gates]
        CL --> ME[metrics] --> SC[score] --> DE[decision]
    end
    core --> OUT["text · JSON · SARIF · Markdown<br/>agent_tasks · scorecard"]
    OUT -. off-gate · advisory only .-> LLM["analyze --llm · config enrich · config init --llm"]
    classDef side fill:#f3f0ff,stroke:#7048e8,color:#000;
    class LLM side;
    style core fill:#e7f5ff,stroke:#1971c2,color:#000;
Loading

archfit doesn't replace architecture review — it makes repeatable evidence cheap to collect and safe to run in CI. It sits one level above single-language boundary linters (dependency-cruiser, import-linter, ArchUnit): they supply facts for one ecosystem; archfit turns facts across languages into one verdict, a Balanced-Coupling risk read, score movement, and agent repair tasks.

Documentation

License

Apache-2.0. See LICENSE.

About

Architecture-fitness CLI for AI agents and CI: deterministic multi-language gates, Balanced Coupling scorecards, SARIF, and agent repair tasks.

Topics

Resources

License

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages