# Architecture Cleanup

> Use when you want to find and remove dead/legacy code, unused endpoints, orphaned data-streams, stale config, or unbuilt proposed-nodes that bloat a repo — a static debloat/cleanup pass over an existing architecture-map. Findings arrive as plain-language cards a non-developer can decide on, and approved findings convert to PRD-ready tracker issues. Triggers — "architecture cleanup", "find dead code from the map", "what can I delete", "debloat this repo", "remove unused endpoints", "clean up the architecture". Default is advisory-only; it touches no source code until you explicitly approve a removal.

- Skill: `martinplarsen/architecture-cleanup` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add martinplarsen/architecture-cleanup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/martinplarsen/architecture-cleanup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: MartinPLarsen (https://skillmd.com/u/martinplarsen)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/martinplarsen/architecture-cleanup

---


# Architecture Cleanup

Analyse an architecture-map (`map.js`) to find what can be safely **removed**, prove each
candidate statically, and paint the findings back onto the map as a red `removable` overlay.

**Core principle — advisor by default.** Step 1 only reads code and annotates the map. It
NEVER edits source. Removal happens only in Step 2, after the user's explicit approval, as a
branch + PR. No runtime telemetry exists, so claims are "no static references found" — never
"unused in production".

## When to use

- "Clean up / debloat the architecture", "find dead code", "what can I delete".
- After mapping a repo and wanting to shrink it before adding features.
- **Not** for line-level perf or refactor proposals — that's `architecture-improve`.
- Recommended order: cleanup → improve (don't optimise code you're about to delete).

## Input — map.js (ADR-010)

The input is `<repo>/architecture-map/map.js` (`window.MAP_DATA`). If it doesn't exist, build
it first with the `architecture-map` skill, then run cleanup on the result. Node file-refs
(`path:line`) and the `status` field are what cleanup cross-checks against the live code.

## Step 1 — advisory pass (default)

1. **Ensure the map exists & is fresh.** No `map.js` → build via `architecture-map`. A stale
   map gives stale findings, so re-map if the repo moved since it was generated.
2. **Git-snapshot the map FIRST (ADR-011).** Before annotating, make sure `map.js` is committed
   (or `git stash`-clean), so backout is one `git restore`. The overlay is additive — original
   node data is only augmented, never overwritten — but the snapshot is the undo guarantee.
3. **Topology layer (deterministic).** Run the helper to get the per-node worklist — inbound/
   outbound edge counts, `isolated` flag, `inboundFrom`, blast-radius, the proposed-node list,
   and duplicate-tech groups:
   ```bash
   node <SKILL_DIR>/analyze-map.mjs <repo>/architecture-map/map.js > /tmp/worklist.json
   ```
4. **Static cross-check (judgment).** For each candidate, grep its `path:line` refs in the real
   code and assign a confidence tier (table below). The helper gives topology; grep gives the
   code half. Dynamic/string-based calls grep can't follow → 🟡, never 🔴.
5. **Bucket into the 7-category taxonomy.** Every finding = `category + tier + evidence
   (path:line + ref-count) + blastRadius`. Build a `findings.json` array (one object per node
   or edge — see helper `--selftest` for the shape). ⚫️ guesses are NOT surfaced.
6. **Write the overlay (additive).** Flag the map's nodes/edges `removable` without touching
   their data:
   ```bash
   node <SKILL_DIR>/apply-overlay.mjs <repo>/architecture-map/map.js /tmp/findings.json > /tmp/map.js \
     && mv /tmp/map.js <repo>/architecture-map/map.js
   ```
   If the repo's viewer predates the overlay, refresh it so the red toggle appears:
   `cp <ARCH_MAP_SKILL_DIR>/assets/index.html <repo>/architecture-map/`.
7. **Report — plain-language finding cards.** Hand the user one plain-language card per finding
   (format: `references/finding-card-and-issues.md` — What it is / Why / What you gain /
   Risk, with the technical evidence folded at the bottom). Grouped by category, then tier.
   Plus the open command: `open <repo>/architecture-map/index.html` shows a 🔴 **Removable**
   toggle (on by default); clicking a node shows tier + evidence + blast-radius.

## Step 1b — PRD-ready tracker issues (on approval)

When the user approves findings (per finding, per category, or "all 🔴"), convert them to
issues in the project's tracker (Linear, GitHub Issues, Jira — via its workflow skill if you
have one). Structure, sub-issue PRD template (Background/Solution/Acceptance criteria/Risk/
Evidence), estimate/label/priority mapping: all in `references/finding-card-and-issues.md`. Parent `Cleanup: <repo> (<date>)` +
one sub-issue per approved finding. Draft the whole batch, show the user titles + estimates,
ONE go creates them. Unapproved findings stay on the map only.
Step 2 (removal) can then execute against the sub-issues with normal status discipline.

## Confidence tiers (static only)

| Tier | Meaning | Condition |
|------|---------|-----------|
| 🔴 **sure** | both signals agree | node `isolated` (no inbound edges) AND grep at its `path:line` finds zero references |
| 🟡 **check-yourself** | can't prove it | refs exist but only from other dead code, OR the call is dynamic (string/reflection/route table) grep can't follow — "you decide" |
| ⚫️ **silent** | pure guess | not surfaced at all |

## Taxonomy (7 fixed categories, D5)

| # | Category | How to detect |
|---|----------|---------------|
| 1 | dead functions | isolated node + 0 grep refs |
| 2 | unused endpoints/routes | route node with no caller edge + no client ref |
| 3 | stale data-streams | edge whose target node is gone from code (flag the **edge**) |
| 4 | unreferenced files/modules | file-ref node nothing imports |
| 5 | stale config/feature-flags/env | config node not read anywhere |
| 6 | unbuilt proposed-nodes | still `proposed`/`status:proposed`, never shipped (`proposedNodes` list) |
| 7 | duplicate/superseded | nodes sharing `tech`/files (`duplicateGroups`) where one supersedes |

## Step 2 — removal (only on explicit approval, ADR-012)

Triggered only when the user says yes (per finding or per category). Ask first — this edits source.

- Emit a **Cleanup-PLAN**, then execute it via an orchestrator ("Lead-dev") + subagents.
  Use your plan-execution + subagent tooling (e.g. the superpowers plugin's executing-plans /
  subagent-driven-development skills, or the Workflow tool) — do NOT build new transport.
- **Lead-dev holds only the plan + task results**, never all file contents (avoids context-bloat).
- **Work-unit = one file/module cluster**, each subagent in its own git worktree
  → no two agents touch the same file.
- **Dependency graph from blast-radius:** independent removals run as a parallel batch; dependent
  ones are removed together by one agent or serialised.
- **Verify per task:** each subagent runs build/tsc/relevant tests + greps "symbol gone" AFTER its
  removal; a break rolls back that task and flags it for the user without blocking the others.
- **Only 🔴 findings are auto-eligible.** 🟡 stays human-only.
- Branch + PR, **never on main, never force**, move-don't-destroy convention where it
  fits. The user reviews the PR before merge.

## Cost (C3)

Step 1 is static and cheap — no gate. Step 2's subagent fan-out warns on scale (finding/agent
count) before firing.

## Helpers

- `analyze-map.mjs <map.js>` — deterministic topology worklist. `--selftest` to verify.
- `apply-overlay.mjs <map.js> <findings.json>` — additive `removable` write-back (ADR-011).
  `--selftest` to verify. `<SKILL_DIR>` = this skill's canonical dir `skills/architecture-cleanup/`.

## Red flags — STOP

- About to edit source in Step 1 → don't. Step 1 is advisory-only.
- About to remove anything without the user's explicit yes → stop, ask.
- About to auto-remove a 🟡 finding → don't. 🟡 is human-only.
- About to overwrite a node's data instead of adding a flag → wrong; the overlay is additive.
- About to work on main → wrong; Step 2 is always a branch + PR.
- About to create tracker issues without the batch-go → stop (Step 1b).
- Report card leads with function names/paths instead of plain language → wrong; evidence goes in the folded block.

