architecture-survey
Skill1 starsChanged 39 days agoMITView on GitHub
Run a domain-first architectural-simplification survey of a mature codebase and turn it into a ranked, tiered, tracker-ready refactoring backlog -- explicitly including the large, scary candidates nobody has had the guts, authority, or time to take on. Use when the user asks to "find architectural improvement opportunities", "survey the codebase for simplification", "find what to refactor away", "tech-debt audit", "what should we simplify next", or wants a ranked refactoring backlog. Survey only -- no refactoring happens inside it.
3 other projects use a version of this.
Adopted by
Most recently taken up by
- Yeachan-Heo/oh-my-claudecodetheir own version, first seen Nov 8, 2026
- Yeachan-Heo/oh-my-claude-sisyphustheir own version, first seen Oct 8, 2026
- alastairlundy/skillstheir own version, first seen Jul 17, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- Yeachan-Heo/oh-my-claude-sisyphus★ 41ksame name
- Yeachan-Heo/oh-my-claudecode★ 41ksame name
- alastairlundy/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository15 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- app-wind-downSkill
- bug-cluster-ledgerSkill
- change-highlightsSkill
- dependabot-batchSkill
- finished-issue-housekeepingSkill
- gauntletSkill
- linearSkill
- markdown-to-pdfSkill
- parallel-checkoutsSkill
- pause-workSkill
- plan-issueSkill
- resume-workSkill
- review-open-itemsSkill
- targeted-specsSkill
The file
We split this skill into the rules it gives an agent
12 rules. 0 are common, 9 are distinctive, and 3 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
9
Distinctive
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 24
Documented confusion is a pre-compiled complexity inventory: Every standing CLAUDE.md warning, memory trap note, glossary apology ("X …
- Distinctive: line 77
Cross-service sibling repos: if the app is one of several services (a sibling redirect/worker service, a shared gem, a devops/schedulers …
- Very specific: line 91
Add a setup task: the user runs a read-only production size query (pg_total_relation_size / row estimates) and pastes results.
- Distinctive: line 98
BEFORE any tracker writes.
- Very specific: line 139
Use the bug-cluster-ledger skill (bundled in this plugin.
- Distinctive: line 195
All findings land under the project's private plans directory.
- Distinctive: line 211
When tracker hygiene is imperfect, this MUST also count fix-shaped merged PRs/commits with no issue reference -- firefighting happens …
- Distinctive: line 270
Create an umbrella epic (a parent issue.
- Distinctive: line 276
Create one parked child issue ("Spin Off Next Survey Batch", lowest / no priority as deliberate parking) that ENUMERATES every remaining …
- Very specific: line 317
Otherwise, the project has none: Never offer to create priority labels, and never propose or apply a lone priority: high, or a label the …
- Distinctive: line 348
The user does not want to judge one now: create it with the not-yet-judged label.
- Distinctive: line 384
Verify any headline claim an agent makes before enshrining it (e.g.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Architecture Survey
A repeatable method for answering "what needless complexity should this project retire, one issue at a time?" The output is a ranked candidate list with full reasoning on a tracker issue, an umbrella epic, a first batch of prioritized child issues, and a parked next-batch issue. Proven start-to- finish in one working day on a ~10-year Rails app.
Calibration lessons (why the method is shaped this way)
These were learned the hard way; do not relearn them:
- Tool passes are evidence, not discovery. flog/flay/debride/lint-todo output surfaces small, local debt and re-derives what churn already says. The large structural candidates come from the domain passes: top-down critique, bug-cluster history, and documented confusion. Weight effort accordingly -- the mechanical pass is a timeboxed appendix, never the centerpiece.
- Documented confusion is a pre-compiled complexity inventory. Every standing CLAUDE.md warning, memory trap note, glossary apology ("X actually means Y"), and keep-in-sync-by-hand checklist exists because the code confused a competent person. Each is one candidate finding, already justified. This pass routinely outperforms every tool.
- A challenge review is mandatory before executing. Dispatch a fresh subagent to cold-read the survey plan. The first draft of the proven run was bottom-up-heavy and would have produced a lint list; the cold read is what aimed it at the big game. Do not skip this because the plan "looks right".
- Size never disqualifies a candidate. The whole point is surfacing refactorings nobody had the authority or nerve to propose. A big candidate earns an honest confidence tier and, when the route is unknown, a spike -- not a quiet omission.
- A legitimate pattern is not automatically debt. "Two of everything" (two API versions, two of a component) reads as the dual-path smell, but parallel public API versions are normal, customer-respecting practice -- serving v1 while customers migrate to v2 is correct. Separate the two questions: does the duality exist (often fine), and is it maintained badly (copy-paste instead of a shared core, security-relevant drift, a half-built-then-abandoned retirement flag)? Only the second is the finding, and its fix is usually "stop maintaining two copies + close the drift," not "kill the old one" -- let real production traffic, not the survey, decide a version's lifecycle. Do not let a tidy narrative flatten a real distinction; a reviewer in the room will call it out.
- Sibling-repo facts go stale silently. A critic reading a sibling repo (the other service, a shared gem) reports whatever that local checkout happens to be pinned at -- which may be months or years behind its remote, producing confident-but-false cross-service claims ("their schema is frozen at 2024"). Re-verify every load-bearing sibling-repo fact against a fresh pull at synthesis time, and prefer stating cross-service claims in a form a teammate can immediately contradict (exact version/commit/date), so a stale read surfaces as a correction, not an enshrined error.
Project inputs (parameterize; never hardcode one project's)
Collect these before starting:
- Tracker access: CLI or API that can list a team's issues since a date (and read/create/update issues). Extend the project's existing tooling if a needed subcommand is missing.
- Telemetry source: APM (New Relic, Skylight, Scout...) credentials if available; error tracker only if a token actually exists -- demote to "conditional" otherwise, do not let the pass stall.
- Runtime: container name / test runner / how to run one-off tools.
- Documented-confusion sources: project CLAUDE.md, agent memory directory, glossary/docs, any hand-maintained sync checklists or impact inventories, plans/gauntlet/review archives. Also any team-wide PM artifact -- recurring-meeting notes (retro/round-table topic lists with vote counts), a standing tech-debt backlog. Weight these ABOVE single-dev plan archives: a topic three people voted up is team-wide corroboration; a private plan file reflects one contributor's slice. When the survey's own archives are one part-time dev's, say so and down-weight them explicitly.
- Cross-service sibling repos: if the app is one of several services (a sibling redirect/worker service, a shared gem, a devops/schedulers repo), list them up front and make "cross-service-contracts" a first-class Phase-0 subsystem. The load-bearing contracts that no repo's CI covers -- shared databases, job-class-name strings scheduled from outside the repo, command strings consumed by another service, a shared gem pinned at different versions per repo -- are a recurring top-severity blind spot, because a rename breaks production, never a test. Give this critic read access to the siblings; keep its findings scoped to THIS repo's side, naming the other side's internals as an explicit blind spot.
- Excluded territory: epics or upgrades that already own their ground. Record them up front for the boundary rule.
- Scale ground-truth (when scale is a hypothesis): local/dev databases
cannot answer "how big is the giant table" (dumps are downsized or broken).
Add a setup task: the user runs a read-only production size query
(
pg_total_relation_size/ row estimates) and pastes results. Until it lands, mark every scale claim "schema-shape inference, prod numbers pending" rather than stalling -- and ride the "which competing writer/scheduler runs last, how often" question along with it (cron cadence often lives in the out-of-repo schedulers). - Approval gate (optional, user-set): some orgs want leadership buy-in BEFORE any tracker writes. If so, the deliverable is a shareable proposal doc first (ranked list + intended epic/story shape + a clearly-separated process-observations appendix), and NO epic/stories are created until approved. Gate this explicitly; do not create tracker items on spec.
Method
Phase 0 -- top-down subsystem critique (run FIRST)
Enumerate the app's major subsystems (typically 5-10). Beyond the obvious domain subsystems, two tags earn a default slot in most apps and are easy to omit: auth-tenancy (authN/authZ, multi-tenant isolation -- security- sensitive, and a missed tenant scope is the top severity rung) and cross-service-contracts (the seams to sibling repos, per the input note).
Give every critic the SAME prompt spine:
- The rebuild question, VERBATIM: "if we rebuilt this today, what would we NOT rebuild, and what does keeping it cost?"
- An explicit dual-path hunt: a new way built without retiring the old (v2 vs legacy, two implementations of one concern) -- and lesson 5's caveat so critics don't flag legitimate parallelism as debt.
- An explicit dead-code hunt in its territory (dead routes, dead screens, never-wired workers, unreachable branches), with every "dead" claim call-site-grepped -- and a reminder that some invokers live OUTSIDE the repo (job-class strings in a schedulers repo, command strings in a sibling service), so "no in-repo caller" is not "dead" until the siblings are checked.
- A cap of 3-5 honestly-sized candidates per critic. This is the single most important anti-lint-list lever at the critic layer: uncapped, a critic fed a file list returns per-file nits that Phase 4's cap never touches.
This produces the hypothesis list every later pass confirms or refutes, and the fixed subsystem tag taxonomy every finding carries.
"This subsystem is healthy -- leave it alone" is a valid and valuable verdict; instruct critics to check churn and bug history before claiming pain (and to spend that verdict generously -- the proven runs found the live core healthy and the rot concentrated at the edges in almost every subsystem).
Phase 1 -- bug-cluster ledger
Use the bug-cluster-ledger skill (bundled in this plugin; its own
SKILL.md governs the details). Key demand: cluster issues UPWARD to root causes per subsystem,
not per-issue tallies, and deliver a "biggest unowned work-generator"
verdict. Its per-cluster counts are rubric axis 1.
Phase 2 -- institutional-memory mining
Mine every documented-confusion source (lesson 2). For each warning/trap/ apology: what confusion it records, what structural change would delete the need for it, size guess. Also mine plan/review archives for hot zones (a plan that spawned 3+ follow-ups marks one) and deferred punch-list items worth resurrecting. Produce a per-subsystem "documentation debt score" (count of standing warnings + traps + sync pairs) -- rubric axis 2.
Phase 3 -- schema + telemetry
Schema crossed against models: misleading names, missing FKs/indexes, validation-vs-schema drift, race-prone in-app counters, integer money columns, write-only columns, and -- critically -- the complete inventory of stored-but-derivable state (running totals, cached balances, satisfied flags). Stored-derivable drift is a recurring root cause across projects. Telemetry: top transactions by duration and throughput, crossed against churn -- friction = slow AND high-churn. Look past already-filed per-endpoint issues for structural patterns ("every report is slow for one shared reason").
Phase 4 -- mechanical-metrics appendix (timeboxed ~2h)
One agent: churn x complexity quadrant (git churn since the window start
crossed with flog per-file totals), flay top-10 with real-vs-idiomatic
verdicts, lint-todo structural skim, dependency/gem skim for stack-level
liabilities and upgrade-blocking pins, routes-vs-actions cross-check, and at
most a 15-minute dead-code-tool skim. Cap at 10 findings. A lint-todo file
(rubocop_todo / standard_todo) is worth more than its reputation: its waivers
cluster by subsystem and include correctness cops (removed-API idioms,
duplicate-method shadowing, request-reachable open()), so it doubles as a
map of the legacy layer -- skim it by cop family, not by file. Tool recipes:
- Install analysis gems as one-offs inside the container (
gem install flog flay debride --no-document); binstubs are often off PATH -- invoke viaruby -S flog .... Installs are container-ephemeral. NEVER add survey tooling to the project's Gemfile. - Expected yields, from the proven runs: flog = good trend numbers and outlier detection (top-5 by flog maps onto the real friction set, and it catches when the most-complex file is actually dead); the routes-vs- actions static cross-check punches far above its weight (dead route blocks, routes pointing at deleted controllers) and is cheap enough to be a standing CI guard; flay = usually one real cluster among ten hits (worth a quarterly run, not per-PR); debride = ~95% false positives on Rails (controller actions, Pundit predicates, view-called helpers) -- the per-candidate manual grep is the real tool, and grepping class names off the flog list finds its few real hits faster. Closing step (below) turns these yields into a CI-integration decision: flog + routes-check are the usual keepers.
Findings discipline (all passes)
All findings land under the project's private plans directory. For a small run, ONE shared findings file; for a large fan-out (10 critics + 4 phases), prefer one file PER pass in a findings/ subdirectory plus ONE synthesis file that dedupes and ranks -- archive each pass's raw output as it lands so a long run's context does not have to hold every pass at once. Every finding carries: subsystem tag, suspected root cause (one line), honest size (small / medium / large-scary), and evidence. Tool passes cap at top-10. Dedupe happens at synthesis, where the same root cause surfacing from multiple independent passes is the STRONGEST ranking signal -- note the corroboration explicitly on the candidate.
Synthesis -- scored, not vibes
Score each deduped candidate on four countable proxies:
- Tracker issues attributable to it in the survey window (Phase 1 output). When tracker hygiene is imperfect, this MUST also count fix-shaped merged PRs/commits with no issue reference -- firefighting happens off-tracker, and counting only filed issues biases the ranking toward well-ticketed subsystems (Phase 1 handles the mining).
- Standing warnings/traps/sync-pairs it necessitates (Phase 2 output).
- Severity ladder, project-tuned. Put two rungs at or near the top that are easy to forget: a cross-tenant / security leak (in a multi-tenant app this outranks almost everything) and irrecoverable data loss (dropped raw events can never be rebuilt; a reporting bug over intact data can) -- both above re-derivable correctness. Then the domain ladder (e.g. money-out-the-door > report > receipt > cosmetic).
- Cost: estimated phased-PR count at the house PR-size norm, plus two hazard flags: [BACKFILL] (a data migration, historically the expensive part; a backfill on a giant table is its own severity class) and [NO-NET] (the candidate sits in low-coverage territory with no spec net, so it costs materially more PRs and carries more risk -- this is where a "low coverage feeds fear" hypothesis actually bites the ranking).
Recurring root-cause archetypes worth naming so critics hunt them by name and synthesis dedupes them fast (seen across proven runs): stored-derivable drift (a running total / cached balance / flag stored instead of derived, kept in sync by hand -- often with NO framework counter_cache, sometimes with two writers disagreeing); dual-path-without-retiring (lesson 5); eval-of-DB-strings (logic stored as source text in a column and eval'd -- unversioned, untestable, un-greppable, un-renamable); write-only pipeline after UI removal (a feature's UI was deleted "for now" but its whole compute pipeline still runs, burning money on data nothing reads); contract-outside- CI (a rename breaks another repo / a scheduled job / production, never a test).
Assign confidence tiers:
- Tier A -- ready issue: scoped, route known, could start Monday.
- Tier B -- epic with phases: root cause certain, route follows a pattern the project has already proven.
- Tier C -- spike issue: candidate is real, route unknown; the deliverable is a timeboxed spike whose output is the epic. The biggest candidates mostly land here, deliberately -- a spike is more honest than a speculative five-phase epic sketched from a survey-level look.
Boundary rule: a candidate half-overlapping excluded territory is in scope only if it survives with the excluded epic fully done; state the residual explicitly. Purely incidental evidence about an excluded epic goes to that epic as a comment.
Deliverable shape
- If an approval gate is set (see inputs): the FIRST deliverable is a shareable proposal doc, not tracker items. It carries the ranked list, the intended epic/story shape, and a clearly-LABELED process-observations appendix kept out of the code ranking (see below). Steps 1-4 happen only after approval. Also useful even without a gate: a strategy-briefing variant of the same material for a technical audience, framed around the decisions they can make (capacity allocation, sequencing, the process bottleneck) -- different doc, different job, than the approval artifact.
- The ranked list with FULL reasoning goes on the tracker issue itself -- self-contained, never a pointer to private plan files. (Under an approval gate this happens post-approval; the private synthesis file is the interim canonical record.)
- Create an umbrella epic (a parent issue; short title). The survey issue becomes a completed child of it -- a Done survey must not be the parent of unstarted implementation work.
- Spin off the agreed first batch as children of the epic (Tier A issue / Tier B epic / Tier C spike), each with a proposed priority and the project/billing bucket confirmed by the user per candidate.
- Create one parked child issue ("Spin Off Next Survey Batch", lowest / no priority as deliberate parking) that ENUMERATES every remaining ranked candidate in full -- nothing may depend on someone re-reading the survey to know what is left.
- Closing step: judge each one-off metrics tool by this run's actual yield and decide whether any earns permanent CI/rake integration; file an issue if so.
On GitHub Issues, where the project has priority labels, every issue steps 2 to 5 create is shown first as a draft -- the epic, each first-batch child, the parked issue, and step 5's tooling issue -- with one proposed priority label and a one-line reason under its title, and nothing is created until the user answers. Where it has none, say nothing about priority. Read the repository's labels with a limit before drafting:
gh label list --limit 200 --json name,descriptionWithout --limit, gh label list returns 30 labels, oldest first, and
a priority scale added later is not among them. A read that returns
exactly 200 may have been cut short the same way: raise the limit and
read again. Then take the first of these that fits:
- The project declines them in its checked-in CLAUDE.md (or a rules file every session loads), with a statement that the project does not use priority labels on its GitHub issues. It has none, even when the repository has some. Prose about priorities in general is not a decline, and neither is anything said in conversation.
- Otherwise, the project states its set in those files: which labels are its priority levels, and which one means nobody has judged the issue yet. Use the stated labels the read returned, and tell the user of any the repository does not have. With fewer than two levels among them, the project has none.
- Otherwise, the name test: the labels whose names start with
priorityfollowed by the same separator (:,/,-, or a space), in any case. Among them, one whose value isuntriaged,triage, orneeds triage, its words joined by a space, a hyphen, or an underscore, is the not-yet-judged label, and the rest are the levels. Two or more levels make a scale, and fewer make none. - Otherwise, the project has none. Never offer to create priority
labels, and never propose or apply a lone
priority: high, or a label the name test does not match (P1,urgent), as a priority, whatever is said about such labels in conversation.
Where the project has them, show all the drafts in one message, each as
its title, then Priority: <label> -- <one-line reason>, then its body,
and stop:
- One level per issue, never two candidates, and never the
not-yet-judged label. Choose each from the labels' own descriptions,
or from their names where a description is empty, and the survey's
evidence for that candidate, so the project's meanings decide; this
skill carries no scale of its own. Where the descriptions and names do
not say which end of the scale is the higher (
priority: 1,priority: 2, no descriptions), ask before proposing, and create nothing in that turn. - The epic proposes the highest level proposed for any of its children, since the children's evidence is the epic's. It is a proposal like the rest: a change to a child's level in the answer does not change the epic's.
- The parked issue proposes the project's lowest level. Parking is a judgment, and the not-yet-judged label says nobody has made one.
- Never run
gh issue createin the turn that drafts the issues. A level applied before the user has seen it is a judgment made for them. Approving the drafts confirms each label: create each issue from its body, without itsPriority:line, with exactly its label (--label "<label>"). A different level in the answer replaces that issue's, and an answer that changes some levels and objects to nothing else confirms the rest. Approval of the proposal document under an approval gate is not this answer: the drafts are shown after it. - The user does not want to judge one now: create it with the not-yet-judged label. Where the project has levels and no such label, create it with no priority label and say so.
- After each
gh issue create, read the new issue's labels back (gh issue view <number> --json labels). A filer without permission to label can get the issue without its labels and no error. When a priority label was passed and is not on the issue, put the proposal at the top of the issue's body:gh issue edit <number> --body-file <file>replaces the whole body, so the file holds the draft'sPriority:line, a blank line, and then the body as created. Say that the label did not land.
On a GitHub project with no priority labels, step 3's "proposed priority" and step 4's "lowest / no priority" have nothing to carry them: write no priority into an issue's body or the reply, and apply no label for one. Those two phrases stay as written for a tracker with a priority field of its own, such as Linear.
Process observations are NOT code candidates. A survey routinely surfaces organizational costs -- merge/deploy gatekeeping, interrupt-driven priority churn, unfilled ownership roles. These are real and worth surfacing, but they must never be laundered into refactoring stories or scored on the code rubric. Quarantine them in a labeled appendix (of the proposal, or a comment on the survey issue) addressed to the people who own process. When the bug-cluster pass can attach hard numbers -- approved-to-merged latency, count of approvals rotting >60 days, started-but-not-finished age distribution, share of merged PRs with no issue -- put those in the appendix; they turn "it feels slow" into a decision-ready fact. Note the one bridge: the code-addressable half of a "fear of change" hypothesis (missing contract tests, dead code, no test net, backfill hazards) DOES feed candidates; only the organizational residue goes to the appendix.
Execution notes
- Phases 1-4 fan out as parallel subagents once Phase 0 has fixed the taxonomy; Phase 0 itself parallelizes per subsystem.
- Verify any headline claim an agent makes before enshrining it (e.g. "zero production callers" gets a fresh grep).
- The survey changes no production code, so there is no test/lint/PR tail -- but tooling improvements it needs (a tracker-CLI subcommand, say) are fair game and should be built properly, not worked around.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

