Content
# Archdo
Architectural quality checker for Elixir. Catches what Credo (style), Dialyzer (types), and Sobelow (security) miss: structural issues, SOLID violations, OTP anti-patterns, boundary enforcement, and some LLM code slop.
**340 rules** across 12 categories. Every finding includes a `why`, ranked fix suggestions, and structured context.
## What it checks
| Category | Rules | Examples |
|----------|-------|----------|
| **Boundaries & Architecture** | 37 | Dependency direction, context encapsulation, boundary leak detection (internal modules called from outside, schemas/processes/config crossing contexts), circular deps, chatty boundaries, unvalidated params, reverse dependencies, query in interface, shared DB/ETS tables, LiveView logic, N+1 preload, dev dep hygiene, MVC-style layout, circuit breakers in context modules, compiled: cross-boundary calls, blast radius, orphan modules |
| **Public API & Documentation** | 3 | Missing module/function docs, missing typespecs, external calls into private modules, contract density on schemas and supervisors, typed structs at boundaries, primitive obsession |
| **Single Source of Truth** | 7 | Type-2/3 clones, scattered config, reinvented enumerable, removed `Mix.Config` API |
| **Coupling & Abstraction** | 30 | Behaviour size, broad imports, unused deps/aliases, mockability, feature envy, speculative generality, missing telemetry, N+1 queries, compiled: unused imports, weak deps, phantom deps |
| **Change Economy** | 33 | Building-block quadrant policy, hidden coupling, churn hotspots, abstraction leakage, change amplifiers |
| **OTP Process Architecture** | 71 | Blocking callbacks, unsupervised processes, GenServer anti-patterns, restart mismatches, stale PIDs, deadlock, callback sprawl, atom exhaustion, ETS/DETS cleanup, sequential-where-parallel, telemetry/observability gaps, async metadata loss, sensitive state without format_status, socket-active-true |
| **Module Quality** | 101 | Complexity, recursion (4 rules), LLM slop detection (5 sub-checks), dead functions, performance traps (8 rules: string concat, list ops, collection waste, regex, keyword lookup), nested control flow, boolean blindness, stub detection, shadowed clauses, over-eager evaluation (6 sub-checks), sensitive data exposure (6 sub-checks), error-handling sub-rules, idiomatic-form rewrites (`then/2`, `tap/2`, `Map.fetch/2`, `flat_map`, `frequencies_by`, etc.), security primitives (constant-time compare, JSON atom DoS, fragment SQL injection, hand-rolled crypto in auth, eval in production) |
| **Test Architecture** | 33 | Coverage gaps, over-mocking, empty describe, missing error paths, untested modules, process leaks, flaky indicators, assert on implementation, Mox `stub`/`expect` discipline, async timeout safety, `errors_on/1` vs raw access |
| **Event Sourcing** | 9 | Aggregate purity, projection isolation, event immutability, command/event naming, event/command struct versioning |
| **State Machines** | 6 | Unreachable states, terminal state integrity, implicit boolean state, transition-target validation, declared-state set membership |
| **Composition & Composability** | 6 + verdicts | Deep `use` chains, excessive namespace depth, pipeline order flips, side-effect terminators, cross-module shape mismatches, ordered-middleware-chain constraints, per-module and per-context building-block verdicts scoring each public function on six composability axes (input closure, determinism, output completeness, totality, side-effect freedom, errors-as-values) |
| **NIF Safety** | 4 | Panic-inducing Rust patterns, scheduler misuse, missing behaviour wrapping |
*Total: 340 unique rule IDs. Counts derived directly from the rule registries (`Archdo.DocCoverage.registered_rule_ids/0`); each rule appears under its primary category only.*
### Building-block tests
Beyond rule-based findings, Archdo scores every public function and rolls the scores up into per-module and per-context verdicts — flagging modules and contexts whose interfaces are too tangled, too partial, or hidden behind side effects. A context passes only when every module under its namespace passes.
### LLM slop detection
Detects patterns of unnecessarily verbose code typically generated by LLMs — docs on private functions, trivial delegation wrappers, redundant boolean comparisons, empty doc strings, single-step pipelines — paired with rules for dead private functions, unused aliases, identity transformations, and verbose ok/error unwrapping. Together they let Archdo systematically find and remove AI-generated slop.
## Using with Claude Code (recommended)
Archdo works best as part of a **two-layer review** with Claude Code and the [Elixir skill](https://github.com/BadBeta/Elixir_skill):
1. **Layer 1 — Archdo** finds structural issues mechanically (fast, exhaustive)
2. **Layer 2 — Elixir skill** provides domain judgment on whether findings are real issues or intentional trade-offs
### Setup
**Step 1: Install the Elixir skill** (gives Claude Code deep Elixir knowledge):
```bash
cd ~/.claude/skills
git clone https://github.com/BadBeta/Elixir_skill.git elixir
```
**Step 2: Clone Archdo** (or add as a dependency to your project):
```bash
git clone https://github.com/BadBeta/archdo.git ~/Projects/Archdo
cd ~/Projects/Archdo && mix deps.get
```
**Step 3: Use it.** Ask Claude Code to review any Elixir project:
> "Check the architecture of /path/to/my_project using Archdo"
Claude will:
1. Run `mix archdo --paths /path/to/my_project/lib` for structural analysis
2. Load the Elixir skill and relevant subskills (OTP, architecture, testing, error handling) to evaluate each finding with deep domain knowledge
3. Present the issues alongside judgment on which matter and how to fix them idiomatically
The Elixir skill's subskills contain the specialized knowledge that makes Layer 2 work — OTP process patterns, architecture decision frameworks, Ecto conventions, error handling idioms, and more. Always use `/elixir` to ensure the skill is loaded before reviewing findings.
### MCP server (for deeper LLM integration)
For projects that want Archdo available as an MCP tool:
```json
// .mcp.json in your project root
{
"mcpServers": {
"archdo": {
"command": "mix",
"args": ["archdo.mcp"]
}
}
}
```
This exposes the analysis tools: `archdo_analyze_paths`, `archdo_analyze_file`, `archdo_deep_review`, `archdo_list_rules`, `archdo_explain_rule`, `archdo_health`, `archdo_diff`, `archdo_diagram`, `archdo_perf_audit`, `archdo_suggest`, `archdo_explain_finding`, `archdo_stats`. Tool inputs are validated against their JSON Schema definitions using JSV. Archdo focuses on detection and diagnosis — applying fixes is left to the user (or to LLMs with access to the elixir-implementing skill).
## Quick start
### As a Mix dependency
```elixir
# mix.exs
def deps do
[{:archdo, github: "BadBeta/archdo", only: [:dev, :test], runtime: false}]
end
```
```bash
mix archdo # scan lib/ (summary table, boundaries + functions enabled)
mix archdo --format compact # one-line-per-finding
mix archdo --format html # standalone HTML report
mix archdo --format sarif # GitHub Code Scanning integration
mix archdo --paths lib/my_app/accounts # scan specific paths
mix archdo --only 4.17,6.12 # run specific rules
mix archdo --since main # only files changed since git ref (PR review)
mix archdo --explain 6.50 # explain a rule
mix archdo --init # generate .archdo.exs config
mix archdo --watch # re-run on file changes
mix archdo --compiled # compiled beam analysis (dead code, blast radius)
mix archdo --coverage # test coverage gap matrix
mix archdo --metrics # Martin package metrics matrix
mix archdo --building-blocks # per-module building-block verdicts
mix archdo --diagram context # render Mermaid / interactive HTML diagrams
mix archdo --packs ce_compliance # opt into Change Economy rule packs
mix archdo --list-packs # list available rule packs
mix archdo --ignore 4.17,6.12 # exclude rules from a run
```
### Scan any project without installing
You can also scan external projects from an Archdo checkout:
```bash
cd /path/to/archdo
mix archdo --paths /path/to/other_project/lib
```
### Suppress specific findings
Add a comment on the line above the finding:
```elixir
# archdo:allow 3.1
defp subscribe, do: Phoenix.PubSub.subscribe(MyApp.PubSub, @topic)
```
## Dependencies
- **Jason** — JSON encoding for MCP and output formats
- **JSV** — JSON Schema validation at MCP boundary (tool input validation)
## Output formats
| Format | Use for |
|-----------|---------|
| `summary` | Default — markdown pipe table grouped by rule (best for overview) |
| `text` | Terminal review — grouped, color-coded, full explanations |
| `compact` | grep/CI — one line per finding |
| `json` | Dashboards, CI integration |
| `llm` | NDJSON with markdown for LLM consumption |
| `sarif` | GitHub Code Scanning — shows findings inline on PRs |
| `html` | Standalone dark-theme HTML report with expandable details |
## Baseline / freeze
Accept existing violations and only flag new ones:
```bash
mix archdo --freeze # save baseline
git add .archdo_baseline.exs
mix archdo # only new violations shown
mix archdo --freeze-stats # track progress
```
## Detection and diagnosis only
Archdo is intentionally not a fix-applying tool. The job is to detect structural problems, explain *why* each one matters, and rank fix options. Applying those fixes is your decision — or, in an LLM-assisted workflow, the LLM's responsibility once it's loaded the appropriate Elixir skill (`elixir-implementing` for general fixes, `phoenix` / `phoenix-liveview` for framework files, `elixir-planning` for architecture-level redesigns).
This split keeps Archdo deterministic and auditable — every diff in your project is a human (or LLM) decision, not a tool's auto-edit.
## Documentation
- **[GUIDE.md](GUIDE.md)** — comprehensive user guide
- **[ARCHITECTURE_RULES.md](ARCHITECTURE_RULES.md)** — all 340 rules documented
## License
MIT.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.