archfit

module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: Apache-2.0

README

archfit

CI Release Version GHCR Image Size Go Reference Go Report Card License

Architecture-fitness CLI that gives AI coding agents and CI a deterministic, machine-readable view of architecture drift across Go, TypeScript, and Python.

Why archfit

An AI agent editing your repo cannot see your architecture. It sees files. So it adds an import from the domain layer into the HTTP adapter, breaks a module boundary, or grows a cycle — and the diff looks fine. archfit makes the architecture a fact the agent (and your pipeline) can check.

Without archfit — the agent's loop has no architecture signal:

agent edits files → tests pass → PR opened → boundary leak ships → reviewer
catches it days later (or doesn't)

With archfit — the same loop closes on structured, repairable feedback:

agent edits files → archfit check --format sarif → boundary violation +
agent_tasks repair block → agent fixes the import → check is clean → PR opened

archfit reads dependency facts from the repository, compares them with .archfit.yaml, and emits findings as SARIF, JSON, Markdown, or text — plus agent_tasks blocks an agent can act on directly. Gates are deterministic: byte-identical output for unchanged input, no LLM on the gate path.

Every gate violation ships an agent_tasks entry — a structured repair order, not a log line the agent has to parse intent out of:

{
  "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 check -c .archfit.yaml --full"]
}

The goal, the constraints it must stay inside, the exact files, and the command that proves the fix — everything an agent needs to close the loop unattended.

What you get

  • Deterministic gates for forbidden dependencies, public-API boundaries, layer direction, import cycles, and configured thresholds.
  • agent_tasks repair blocks so an AI agent gets the fix, not just the error.
  • A banded 7-dimension scorecard (archfit score) aligned to an architecture rubric: boundary integrity, coupling balance, dependency-graph health, cohesion, change locality, architecture fitness, analysis confidence.
  • Balanced-Coupling advisories — strength × distance × volatility, grouped into rollups instead of one line per edge.
  • Honest coverage — when a tool is missing the dependent metric reports n/a with the enable step; runs never fail because an optional analyzer is absent.
  • Baselines so accepted current debt does not hide new findings.
  • Off-gate LLM narration (archfit review, archfit enrich) that may only narrate and prioritize collected evidence — never invent gate violations.

How it compares

archfit is not a replacement for language-specific boundary linters — it is the multi-language, agent-facing layer above them.

Tool Languages Output for agents/CI Coupling model LLM narration
archfit Go, TS/JS, Python SARIF + JSON + agent_tasks + score Balanced Coupling (S/D/V) off-gate
dependency-cruiser TS/JS JSON/HTML, rule violations rule-based no
import-linter Python text, contract pass/fail layered contracts no
ArchUnit Java/JVM (.NET/TS) test assertions in the build rule-based no

Use a single-language linter when you live in one language and want fine-grained, in-build assertions. Use archfit when you want one config and one machine-readable verdict across a polyglot repo, scored and shaped for an agent loop.

Quick start

Install the CLI (use a release tag, not @latest, in repeatable docs):

go install github.com/alexei-led/archfit/cmd/archfit@v0.4.0

Or run the Docker image with the bundled toolchain:

docker run --rm -v "$(pwd):/repo" ghcr.io/alexei-led/archfit:v0.4.0 \
  check --config /repo/.archfit.yaml --full

Run the first check in a repository:

archfit doctor                                   # check available analyzers
archfit init --root . --output .archfit.yaml     # generate a starter config
$EDITOR .archfit.yaml
archfit check --config .archfit.yaml --full      # run the gates
archfit score --config .archfit.yaml --full      # banded scorecard

Accept current findings as a baseline when they represent known debt:

archfit baseline --full --config .archfit.yaml

Starter configs for common project shapes live in examples/. Need Docker, CI, optional analyzers, or language-specific setup? Start with the guide.

Core commands

Command Use
archfit doctor Check local analyzer/tool availability.
archfit init Generate a starter .archfit.yaml.
archfit update Sync .archfit.yaml with current structure.
archfit check Run architecture gates and metrics.
archfit score Emit the banded 7-dimension scorecard.
archfit scan Produce a full Markdown audit report.
archfit baseline Save accepted current findings.
archfit review Off-gate LLM narrative review of the evidence.
archfit enrich Draft off-gate LLM coupling-label refinements.
archfit explain <id> Explain one finding by fingerprint prefix.
archfit install Check or install optional language tools.

See the commands guide for formats, exit codes, and examples.

Model

archfit operationalizes the parts of Vlad Khononov's Balanced Coupling model that can be checked from code, configuration, and git history — integration strength, socio-technical distance, and volatility — to explain why a relationship is balanced (cohesion, the good coupling) or risky (cascading changes, distributed-monolith risk).

It does not replace architecture review. It makes repeatable evidence cheap to collect and safe to run in CI. For the mapping from theory to signals, see Concepts and Metrics.

Documentation

License

Apache-2.0. See LICENSE.

Directories

Path Synopsis
cmd
archfit command
enrich: the off-gate LLM workflow that drafts coupling-strength label refinements for human review.
enrich: the off-gate LLM workflow that drafts coupling-strength label refinements for human review.
internal
agenttask
Package agenttask assembles the structured repair-task block (spec §13) from gate findings.
Package agenttask assembles the structured repair-task block (spec §13) from gate findings.
baseline
Package baseline handles loading and saving the archfit baseline file, which tracks accepted findings and metric snapshots across runs.
Package baseline handles loading and saving the archfit baseline file, which tracks accepted findings and metric snapshots across runs.
calibrate
Package calibrate compares two coupling scorers over a coupling.Index and reports per-edge agreement between them.
Package calibrate compares two coupling scorers over a coupling.Index and reports per-edge agreement between them.
classify
Package classify assigns Balanced Coupling classifications to graph edges: strength, distance, volatility, and explicitness.
Package classify assigns Balanced Coupling classifications to graph edges: strength, distance, volatility, and explicitness.
config
Package config defines the Config struct, its view projections, and the Load function that parses and validates an archfit.yaml configuration file.
Package config defines the Config struct, its view projections, and the Load function that parses and validates an archfit.yaml configuration file.
engine
Package engine implements the pipeline orchestrator that runs extractors, classify, rules, status, metrics, and renderers in sequence.
Package engine implements the pipeline orchestrator that runs extractors, classify, rules, status, metrics, and renderers in sequence.
extract/astgrep
Package astgrep implements the ports.PatternProvider port for ast-grep.
Package astgrep implements the ports.PatternProvider port for ast-grep.
extract/clones
Package clones provides a clone-detection runner that identifies duplicated code blocks across files.
Package clones provides a clone-detection runner that identifies duplicated code blocks across files.
extract/complexity
Package complexity provides a cyclomatic-complexity runner that collects per-function CCN values via the external lizard tool.
Package complexity provides a cyclomatic-complexity runner that collects per-function CCN values via the external lizard tool.
extract/deployunit
Package deployunit detects deploy units in a repository by scanning for Go main packages, TypeScript package.json workspaces, Python pyproject.toml, Dockerfiles, and Kubernetes Deployment/StatefulSet manifests.
Package deployunit detects deploy units in a repository by scanning for Go main packages, TypeScript package.json workspaces, Python pyproject.toml, Dockerfiles, and Kubernetes Deployment/StatefulSet manifests.
extract/dynimports
Package dynimports detects dynamic/lazy imports that are invisible to the static dependency graph: Python non-top-level (in-function) `import`/`from`, `importlib.import_module` / `__import__`, and TypeScript `require()` / dynamic `import()`.
Package dynimports detects dynamic/lazy imports that are invisible to the static dependency graph: Python non-top-level (in-function) `import`/`from`, `importlib.import_module` / `__import__`, and TypeScript `require()` / dynamic `import()`.
extract/gitnexus
Package gitnexus provides an optional dependant-count provider backed by the gitnexus CLI's knowledge graph.
Package gitnexus provides an optional dependant-count provider backed by the gitnexus CLI's knowledge graph.
extract/golang
Package golang implements the Go import extractor using golang.org/x/tools/go/packages.
Package golang implements the Go import extractor using golang.org/x/tools/go/packages.
extract/loc
Package loc counts source-file line counts for the structural_weight metric.
Package loc counts source-file line counts for the structural_weight metric.
extract/py
Package py implements the Python import extractor using grimp.
Package py implements the Python import extractor using grimp.
extract/runtime
Package runtime detects async/message-bus integration patterns in a repository.
Package runtime detects async/message-bus integration patterns in a repository.
extract/scip
Package scip implements the ports.SymbolResolver port using SCIP indexers.
Package scip implements the ports.SymbolResolver port using SCIP indexers.
extract/ts
Package ts implements the TypeScript import extractor using dependency-cruiser.
Package ts implements the TypeScript import extractor using dependency-cruiser.
facts
Package facts assembles per-module structural facts from already-collected data (symbol graph, file LOC, co-change history, optional gitnexus impact).
Package facts assembles per-module structural facts from already-collected data (symbol graph, file LOC, co-change history, optional gitnexus impact).
fitness
Package fitness detects architecture-intent ENFORCEMENT signals in a repository.
Package fitness detects architecture-intent ENFORCEMENT signals in a repository.
history/git
Package git provides functions for reading git history: changed files between refs, the HEAD ref, repo root, and a churn stats stub.
Package git provides functions for reading git history: changed files between refs, the HEAD ref, repo root, and a churn stats stub.
initcfg
Package initcfg discovers project structure and renders a starter .archfit.yaml.
Package initcfg discovers project structure and renders a starter .archfit.yaml.
labels
Package labels holds the pure logic for pinned coupling-strength labels — the human-reviewed output of `archfit enrich`.
Package labels holds the pure logic for pinned coupling-strength labels — the human-reviewed output of `archfit enrich`.
labels/labelsio
Package labelsio is the I/O adapter for pinned coupling labels: it reads and validates .archfit-labels.yaml from disk.
Package labelsio is the I/O adapter for pinned coupling labels: it reads and validates .archfit-labels.yaml from disk.
llm
Package llm is the thin off-gate LLM provider layer for archfit's enrich and explain commands.
Package llm is the thin off-gate LLM provider layer for archfit's enrich and explain commands.
metrics
Package metrics defines the Metric interface, the generic Calculator[In] adapter, and the New() registry.
Package metrics defines the Metric interface, the generic Calculator[In] adapter, and the New() registry.
metrics/boundary
Package boundary implements the five boundary-health metrics: encapsulation, unbalanced_edge, cycle, coverage, and change_locality.
Package boundary implements the five boundary-health metrics: encapsulation, unbalanced_edge, cycle, coverage, and change_locality.
metrics/internal/modgraph
Package modgraph provides the shared module-level graph and history helpers used by the modularity metrics: collapsing nodes/files to module units, aggregating churn, and computing SCC-condensed blast radius.
Package modgraph provides the shared module-level graph and history helpers used by the modularity metrics: collapsing nodes/files to module units, aggregating churn, and computing SCC-condensed blast radius.
metrics/internal/result
Package result provides shared scoring helpers for the metrics layer: band names, confidence constants, mode constants, and the utility functions that map scores to bands, apply confidence caps, compute deltas, and build indeterminate (n/a) count results.
Package result provides shared scoring helpers for the metrics layer: band names, confidence constants, mode constants, and the utility functions that map scores to bands, apply confidence caps, compute deltas, and build indeterminate (n/a) count results.
metrics/intramodule
Package intramodule holds the intra-module quality metrics — signals about the internals of a module (function complexity, architecture-enforcement presence) rather than its coupling to other modules.
Package intramodule holds the intra-module quality metrics — signals about the internals of a module (function complexity, architecture-enforcement presence) rather than its coupling to other modules.
metrics/metricstest
Package metricstest provides shared test helpers for metric family packages.
Package metricstest provides shared test helpers for metric family packages.
metrics/modularity
Package modularity implements the modularity metrics (blast_radius, change_amplification, hidden_coupling, structural_weight, cohesion_lcom) and the functional_candidates metric.
Package modularity implements the modularity metrics (blast_radius, change_amplification, hidden_coupling, structural_weight, cohesion_lcom) and the functional_candidates metric.
metrics/risk
Package risk implements the risk_hub architecture metric, which surfaces modules whose cross-module symbol-surface breadth and explicit config volatility identify the highest-risk coupling hubs.
Package risk implements the risk_hub architecture metric, which surfaces modules whose cross-module symbol-surface breadth and explicit config volatility identify the highest-risk coupling hubs.
model/clone
Package clone holds the neutral value types for clone-detection results so that core-ring packages (e.g.
Package clone holds the neutral value types for clone-detection results so that core-ring packages (e.g.
model/coupling
Package coupling defines the Balanced Coupling classification types: Strength, Distance, Volatility, Explicitness, and the Classification index.
Package coupling defines the Balanced Coupling classification types: Strength, Distance, Volatility, Explicitness, and the Classification index.
model/diagnostic
Package diagnostic defines the top-level output contract: Diagnostic, MetricResult, Verdict, and the supporting summary and coverage types.
Package diagnostic defines the top-level output contract: Diagnostic, MetricResult, Verdict, and the supporting summary and coverage types.
model/finding
Package finding defines the Finding type and its sealed constructor.
Package finding defines the Finding type and its sealed constructor.
model/graph
Package graph defines the sealed graph types: Node, Edge, and the Build constructor that deduplicates, sorts, and freezes extractor output into a deterministic, immutable Graph.
Package graph defines the sealed graph types: Node, Edge, and the Build constructor that deduplicates, sorts, and freezes extractor output into a deterministic, immutable Graph.
model/pattern
Package pattern defines the shared structural match result type produced by pattern-search ports (PatternProvider) and consumed by rules as evidence.
Package pattern defines the shared structural match result type produced by pattern-search ports (PatternProvider) and consumed by rules as evidence.
model/signal
Package signal defines the carrier types that flow between signal producers (fitness scanner, git history, complexity tool) and the metrics layer: the per-family metric inputs (CommonInput, HistoryInput, SymbolInput, SizeInput, ComplexityInput, FitnessInput, DuplicationInput), the CollectedSignals bag the engine assembles and projects per family, and the RunSignals bundle the cmd layer produces.
Package signal defines the carrier types that flow between signal producers (fitness scanner, git history, complexity tool) and the metrics layer: the per-family metric inputs (CommonInput, HistoryInput, SymbolInput, SizeInput, ComplexityInput, FitnessInput, DuplicationInput), the CollectedSignals bag the engine assembles and projects per family, and the RunSignals bundle the cmd layer produces.
model/symbol
Package symbol defines the domain type for per-symbol metadata extracted from a SCIP (or equivalent) index.
Package symbol defines the domain type for per-symbol metadata extracted from a SCIP (or equivalent) index.
output/console
Package console renders a Diagnostic as clean, LLM-friendly plain text: labelled sections of aligned key/value lines, no box-drawing tables.
Package console renders a Diagnostic as clean, LLM-friendly plain text: labelled sections of aligned key/value lines, no box-drawing tables.
output/jsonout
Package jsonout implements the JSON renderer for diagnostic output.
Package jsonout implements the JSON renderer for diagnostic output.
output/markdown
Package markdown renders a Diagnostic as Balanced-Coupling-aligned Markdown: lint-message advisory format, BC vocabulary throughout, clearly-labeled "Supporting structural metrics (beyond Balanced Coupling)" and "Distance confidence" sections.
Package markdown renders a Diagnostic as Balanced-Coupling-aligned Markdown: lint-message advisory format, BC vocabulary throughout, clearly-labeled "Supporting structural metrics (beyond Balanced Coupling)" and "Distance confidence" sections.
output/sarif
Package sarif renders a Diagnostic as a SARIF 2.1.0 log (spec §12) so CI systems (GitHub code scanning et al.) can surface findings inline on PRs — the agent/CI half of the feedback loop.
Package sarif renders a Diagnostic as a SARIF 2.1.0 log (spec §12) so CI systems (GitHub code scanning et al.) can surface findings inline on PRs — the agent/CI half of the feedback loop.
output/scorecard
Package scorecard renders a Diagnostic as the architect skill's seven-dimension banded scorecard: an overall 0-100 value plus one block per dimension with its value, band, confidence, evidence references, and a one-line summary.
Package scorecard renders a Diagnostic as the architect skill's seven-dimension banded scorecard: an overall 0-100 value plus one block per dimension with its value, band, confidence, evidence references, and a one-line summary.
ownership
Package ownership resolves module owners from CODEOWNERS files or git-author history, producing a module→owner map that fills gaps in config-authored ownership metadata.
Package ownership resolves module owners from CODEOWNERS files or git-author history, producing a module→owner map that fills gaps in config-authored ownership metadata.
ports
Package ports defines the hexagonal port interfaces that separate the engine orchestrator from its adapters.
Package ports defines the hexagonal port interfaces that separate the engine orchestrator from its adapters.
rules
Package rules defines the Rule interface and the built-in rule implementations: forbidden_dependency, public_api_only, forbidden_layer_direction, internal_api_access, new_cross_module_dependency, and cycle.
Package rules defines the Rule interface and the built-in rule implementations: forbidden_dependency, public_api_only, forbidden_layer_direction, internal_api_access, new_cross_module_dependency, and cycle.
scope
Package scope resolves the analysis scope: the repo root, changed files (delta mode), and the mode (full vs delta) for a run.
Package scope resolves the analysis scope: the repo root, changed files (delta mode), and the mode (full vs delta) for a run.
score
Package score synthesises an already-computed Diagnostic into the architect skill's seven-dimension banded scorecard (boundary_integrity, coupling_balance, dependency_graph_health, cohesion_modularity, change_locality, architecture_fitness, analysis_confidence), each with a 0-100 value, a band, a confidence level, and at least one evidence reference.
Package score synthesises an already-computed Diagnostic into the architect skill's seven-dimension banded scorecard (boundary_integrity, coupling_balance, dependency_graph_health, cohesion_modularity, change_locality, architecture_fitness, analysis_confidence), each with a 0-100 value, a band, a confidence level, and at least one evidence reference.
staleness
Package staleness detects map-quality advisory findings: uncovered paths, dead module rules, and stale reviewed_at timestamps.
Package staleness detects map-quality advisory findings: uncovered paths, dead module rules, and stale reviewed_at timestamps.
status
Package status assigns status labels (new, baseline, excepted, expired_exception, fixed) to findings by comparing against a baseline and exception set.
Package status assigns status labels (new, baseline, excepted, expired_exception, fixed) to findings by comparing against a baseline and exception set.
toolrun
Package toolrun defines the Runner interface and its concrete implementation.
Package toolrun defines the Runner interface and its concrete implementation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL