AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Arch Audit

skill-maxenko-claude-skills-arch-audit · by maxenko

Analyzes an entire codebase for architectural smells, spaghetti patterns, tangled dependencies, and structural debt — prescribes concrete refactors grounded in Ousterhout, Fowler, Hickey, Feathers, and connascence theory. Use when the user asks to "audit the architecture", "review the codebase", "find architectural issues", "analyze tech debt", "find spaghetti code", "architectural smells", "why…

No reviews yet
0 installs
21 views
0.0% view→install

Install

$ agentstack add skill-maxenko-claude-skills-arch-audit

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-maxenko-claude-skills-arch-audit)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
26d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Arch Audit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Architecture Audit

You perform expert-grade architectural reviews of entire codebases. Your job is to find the structural problems that make a system hard to change, understand why they matter in CS terms, and prescribe refactors that a senior engineer would actually ship.

Most architectural-review output is useless because it lists every textbook smell indiscriminately. Your output is different: you rank findings by real cost, you cite evidence, and you tell the user what not to bother fixing. ultrathink each judgment call.

Context

  • Scope argument: $ARGUMENTS (if present, restrict audit; otherwise audit whole repo)
  • In git repo: !git rev-parse --is-inside-work-tree 2>/dev/null || echo "not a git repo"
  • Recent activity: !git log --oneline -10 2>/dev/null || echo "no git history available"
  • Tracked files: !git ls-files 2>/dev/null | wc -l | tr -d ' ' || echo unknown

Mental model

Architecture problems come from one root cause: complexity that was added accidentally (Brooks, No Silver Bullet). Your job is separating essential complexity (the problem is hard) from accidental complexity (we made it hard), then locating where the accidental complexity has concentrated.

Four lenses surface almost all real issues:

  1. Coupling — what depends on what, and how strongly (connascence, cycles, fan-in, data coupling, state ownership)
  2. Cohesion & complexity — what lives together, and whether modules are deep or shallow (Ousterhout)
  3. Abstraction quality — do boundaries carve the problem at its joints, or complect unrelated concerns (Hickey); includes failure, observability, and transport seams
  4. Evolution signals — where is churn concentrated, and does that churn match the structure (Tornhill hotspots, co-change)

A finding that does not surface through at least one of these lenses is probably not worth reporting.

When NOT to audit

Architecture review is expensive and can produce noise on the wrong target. Decline or scope down when:

  • Codebase is structure; audit only load-bearing concerns (data integrity, auth, irreversible decisions).
  • No significant change activity (static library, reference implementation) — smells do not cost anything if the code does not move.
  • User already has a plan — they want execution (refactor-pro, plan-execute), not another opinion.

In these cases, say so plainly and offer a narrow scope or a different skill.

Process

Phase 1: Scope and orient

  1. Read the entry points: package.json/pyproject.toml/Cargo.toml/go.mod/pom.xml, README, any ARCHITECTURE.md or docs/. If a CLAUDE.md exists, read it — it often encodes constraints not visible in code.
  2. Classify the system: monolith, modular monolith, microservices, library, framework-based app, data pipeline, frontend SPA, CLI, mixed. Different paradigms have different smells (see references/smell-catalog.md § paradigm adaptations). **Also note whether the system both ingests data from a latency-bound or fallible source (files, DB, sockets, HTTP/streaming feeds, message queues, sensors, large CSV/Parquet/columnar blobs) and serves it to a consumer (a UI, an API, another module, an export). If it does, the ingest→serve path gets a mandatory pass** in Phase 3 — flag it now so you probe it deliberately.
  3. Map the top-level structure: list top-level directories; identify the apparent layering (layered? hex? feature-sliced? flat?).
  4. Identify the stated architecture vs. the actual architecture. The gap is usually where the smells live.
  5. Note the scale: rough LOC, number of top-level modules. Tailor depth of analysis to size — a 5k-LOC service needs different treatment than a 500k-LOC monolith.

If the codebase is large (>50k LOC or >500 files), delegate exploration phases to the Explore subagent to keep the main context clean. Pass specific questions, not "look around."

Phase 2: Gather evidence

Run these probes before forming conclusions. Record concrete numbers — file paths, LOC, import counts, churn counts. Evidence you don't record, you didn't collect.

Static structure:

  • Top-LOC files: find . -name '*.' | xargs wc -l | sort -rn | head -20. Flag files >500 LOC (language-dependent; 300 for Python, 500 for TS/Java, 800 for Go).
  • Fan-in per module: grep -rn "from " | cut -d: -f1 | sort -u | wc -l. Flag modules imported by >20 distinct files OR >10% of all source files.
  • Cycles: look for A imports B and B imports A (directly or transitively). Any cycle is worth investigating (see references/decision-frameworks.md §2 for when it's tolerable vs. fatal).
  • Public-API surface: count exported names per module. Deep modules (Ousterhout) have narrow exports relative to implementation size.

Behavioral evidence (if git is available):

  • Hotspots: git log --format=format: --name-only --since=1.year | grep -v '^$' | sort | uniq -c | sort -rn | head -30. Cross-reference with file LOC: churn × LOC identifies top refactor targets (Tornhill).
  • Co-change: files that consistently change together but live apart suggest a missing module boundary (shotgun surgery). Run git log --name-only and look for recurring file pairs across commits.
  • Authorship: git log --format='%an' -- | sort -u | wc -l per hotspot — diffuse ownership on a hotspot is a design-risk signal.

System-scale probes (essential on any production system):

  • Data coupling: grep schema/ORM files. Does one table have writers in multiple modules? Are there cross-module JOINs? Transaction boundaries spanning modules mean the modules are not actually separate. Shared-DB coupling is often stronger than any import-graph finding.
  • State ownership: search for globals, module-level mutables, singletons, in-memory caches. For each piece of mutable state, identify the single writer. Multiple writers without coordination is an architectural bug.
  • Error boundaries: trace a representative failing call. Is there one retry policy or does each layer retry (latency multiplication)? Is the circuit-breaker at the right boundary? Unbounded propagation and N-way retry amplification are architectural, not tactical.
  • Observability seams: is logging/tracing injected at boundaries (middleware, decorators) or scattered through domain logic? Scattered observability is complecting what the business does with how it is watched.
  • Testability signal: the shape of tests reveals the shape of real dependencies. If the test file for module X mocks >5 distinct collaborators, X is over-coupled. Inverted test pyramids (few unit, many e2e) signal low testability at the unit level.

From this evidence, state 2–4 starting hypotheses — "I suspect X is a God component because Y," "I suspect the HTTP layer and domain are complected because Z." Phase 3 confirms, refines, or refutes each.

Phase 3: Detect smells through the four lenses

Apply each lens to the evidence. For detailed definitions, thresholds, and detection recipes, consult references/smell-catalog.md — load it once at the start of this phase.

Keep SKILL.md summaries tight; the catalog is authoritative.

Lens 1 — Coupling (structural + data + distributed-state): cyclic dependencies; strong connascence across boundaries; god components (high fan-in); shared-DB writers in N modules; multi-writer mutable state; missing single-writer boundary / actor / agent / mailbox processor (state protected by fine-grained locks where one task owning the state via a message queue — MailboxProcessor/GenServer/actor/goroutine+channel/mpsc — would eliminate whole classes of bugs; applies both to partitioned per-key state and to singleton coordinators like rate limiters, pools, schedulers); synchronous call chain that should be async (≥4 sync hops, retry amplification); dual-write without outbox (DB write + publish in one function, no atomicity); missing idempotency boundary (retryable handlers with no dedupe key); implicit long-running workflow / missing saga (multi-step cross-service state with ad-hoc rollback and cron sweeps); event bus as hidden global dependency graph (row-shaped events, no schema registry); inappropriate intimacy; message chains (Law of Demeter); unstable-dependency direction.

Lens 2 — Cohesion & complexity: god classes / large files (>500 LOC); long methods (>50 LOC AND cyclomatic >10 AND >2 levels of nesting); long parameter lists (≥5, esp. same-typed primitives); shallow modules (interface almost as complex as implementation); lasagna (pass-through layers that only rename arguments); divergent change (one file edited for unrelated reasons).

Lens 3 — Abstraction quality (Hickey: what is complected that should be decomplected?): anemic domain model; primitive obsession; unenforced invariants / missing smart constructors (same predicate checked at ≥3 call sites, public constructors accept any shape); illegal states representable (boolean/flag combinatorics where only some combos are legal); shotgun parsing (untyped dicts/JSON crossing ≥2 module boundaries with defensive checks at every layer); missing aggregate (cross-entity invariant with no single enforcement point); complected concerns (business + transport, policy + mechanism, transform + iteration, what + when); functional core, imperative shell absent (decisions interleaved with I/O, tests need many mocks); unidirectional data flow absent (shared state mutated from ≥3 sites with no reducer/dispatcher); implicit state machine / scattered entity state (flags or status mutated by many call sites — refactor to type-state, State pattern, or per-entity actor; common for orders, sessions, tickers, subscriptions); event sourcing gap (audit/history reconstructed from snapshots + shadow tables); CQRS gap (one model optimized for both writes and complex reads, fighting each other); implicit dataflow pipeline (≥4 sequential stages hidden as nested calls); scattered error handling / try-catch pyramid (railway-oriented programming); observability complected with logic; missing domain events (producer directly calls N unrelated subsystems); domain depends on infrastructure / missing ports (domain imports ORM, HTTP, SDKs, clock directly); leaky abstractions; missing anti-corruption layer (vendor/legacy types appear inside the domain); missing bounded contexts; speculative generality (YAGNI); the wrong abstraction (Metz); temporal coupling.

Lens 4 — Evolution signals: hotspot-structure mismatch (top churn is not in domain core); shotgun surgery (co-change across unrelated files); parallel inheritance / parallel switch blocks; temporal coupling without type-state enforcement; fossil/dead code; ownership diffusion on hotspots.

Mandatory pass — data ingestion & serving subsystem

Run this whenever Phase 1 found the system both ingests data from a latency-bound or fallible source (files, DB, sockets, HTTP/streaming feeds, message queues, sensors, large CSV/Parquet/columnar blobs) and serves that data to a consumer (a UI, an API, another module, an export). This is not a fifth lens — it is a promotion rule: when an ingest→serve path exists, the absence of a dedicated, robust, observable abstraction for it is always a finding, ranked by proportionality (Phase 4), never silently dropped. Data movement is where latency, partial failure, and unbounded growth concentrate; "we just read it inline where we need it" is the default and it is almost always wrong at any real scale.

Evaluate the ingest→serve path against this rubric. Each "no" is a candidate finding; load the catalog's § Data ingestion & serving subsystem for detection recipes and the canonical refactor.

  1. Dedicated boundary — is ingestion + serving owned by ONE abstraction (a DataSource/Repository/Store/ingestion engine with a port in domain vocabulary), or is raw I/O (open / parse / query) scattered through UI handlers, controllers, and domain code? Scattered I/O ⇒ there is no seam to make robust. (Lens 3: missing ports; Lens 2: god component absorbing I/O.)
  2. Streaming over load-all — does it stream / window / paginate, or load the whole input into memory before serving? Load-all caps the dataset at RAM and blocks until complete.
  3. Parallelism where the work allows — embarrassingly-parallel ingest (per file / day / shard / partition / key) run sequentially while the CPU idles on I/O wait is wasted throughput. Pipeline the stages (read ∥ decode ∥ index) and bound the concurrency.
  4. Fault tolerance & resumability — one bad record or dropped connection must not abort the whole run. Need: per-unit isolation, retry with backoff + jitter on transient errors only, a resume cursor / checkpoint, idempotent re-ingest (dedupe key), and supervised restart (let-it-crash + supervisor) for the long-lived parts.
  5. IO-latency tolerance & backpressure — is the path async / non-blocking with a bounded queue + explicit overflow policy between producer and consumer? Unbounded buffering turns a slow consumer into an OOM; no backpressure turns a fast producer into a memory bomb.
  6. Observability designed in — does the boundary emit a single, typed lifecycle/status stream (a state machine — see below) plus metrics (latency histogram, throughput, queue depth, error/retry rate, bytes in/out)? This stream is the one source of truth that feeds logs, metrics, AND the UI — not log lines scattered through the parsing code.
  7. If there is a UI — non-blocking + "what are we waiting on" — the latency-bound work must run off the UI thread, and the UI must subscribe to the status stream so it can always tell the user the current phase: Opening… · Connecting… · Reading… · Parsing… · Indexing… · Serving… · Retrying (attempt n)… · Error · Done, ideally with progress / ETA. A UI that freezes during open / connect / process, or that shows a bare spinner with no idea what it is waiting on, is a finding. Progress is data pushed from the boundary, never the UI reaching into I/O.

Prescribe the abstraction (Phase 5). When the rubric shows gaps, the move is almost always the same composition, named explicitly: a pipes-and-filters ingestion pipeline (read → decode → validate → index/store; pure filters, I/O at the endpoints) behind a hexagonal port, driven by a single-writer owner (actor / MailboxProcessor / goroutine+channel / mpsc consumer) that holds the serve-side state and emits a lifecycle state machine the UI consumes via the Observer pattern (signals / event bus / reactive stream). This is not new theory — it is the existing catalog entries (single-writer boundary, pipes-and-filters, functional core / imperative shell, missing ports, unidirectional data flow, observability-at-the-boundary) composed for the I/O subsystem, plus SEDA-style staged concurrency (Welsh, Culler & Brewer, 2001) and Reactive-Streams backpressure. Size the robustness to the profile via references/decision-frameworks.md §13 — a one-shot CLI importer needs far less than a streaming desktop app or a multi-tenant service, but the boundary, the status stream, and non-blocking UI are non-negotiable wherever real I/O latency meets a user.

Then hand off to app-harden. arch-audit fixes the structural gap — that the boundary, the seams, and the event stream exist. Whether that boundary survives production — resource ceilings on the queues / buffers, timeouts on every outbound call, retry-amplification limits, backpressure actually enforced, no secret leakage through the data path, crash-loop safety — is a runtime question. Recommend a follow-up app-harden pass scoped to this subsystem; the two skills compose (arch-audit = where the boundary belongs; app-harden = whether it holds under load).

Evidence discipline at each lens: before you write a finding, record the file path(s), the concrete metric or grep output tha

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.