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.
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;
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.
# 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 errorAccept current known debt as a baseline so it doesn't mask new findings:
archfit baseline --fullStarter configs for common project shapes live in examples/.
Full setup — Docker, CI, optional analyzers, platform packages — is in the
guide.
- One command, many outputs.
archfit analyze→ terminal report (default),--json,--sarif,--markdown, or--format scorecard.--gateturns on CI exit codes; without it the run is report-only. - A decision, not just a score —
HEALTHY/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_tasksrepair blocks so an AI agent gets the fix, not just the error.- A banded
coupling_balancescorecard built on Balanced Coupling (integration strength × distance × volatility), reported as a 0–100 score — optionally gates the build viacoupling.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/awith 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-cacheforces 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).
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;
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.
- Guide — full documentation map and setup.
- Commands —
analyzeflags, formats, exit codes. - Concepts — Balanced Coupling, made executable.
- Metrics — every dimension and how it's scored.
- CI · Agent feedback · Languages · Configuration · Caching
- Contributing
Apache-2.0. See LICENSE.