agentleFS
BULDEEBULDEE/ai-craftsman-superpowers/skills/legacy/SKILL.md

legacy

Skill35 starsChanged 54 days agoApache-2.0View on GitHub

Legacy code rescue - audit hotspots, cover with characterization tests, break dependencies, and plan strangler-fig migrations. Use when inheriting, taming, testing, or refactoring an untested/undocumented codebase.

  • Deletes or force-pushes

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. ajtazer/heckit★ 2same name
    2. tslateman/skills★ 1same 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 repository23 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 8 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    The safety net comes before the refactor: No net, no change.

    line 43
  2. Distinctive:

    Read the relevant files before acting.

    line 47
  3. Very specific:

    When --from is given, use that data as the complexity axis and still compute churn from git (below).

    line 81
  4. Distinctive:

    Confirm it runs: Ask whether the project runs and tests pass locally.

    line 95
  5. Distinctive:

    Use native Mermaid diagrams (no external tool):

    line 120
  6. Very specific:

    Every finding cites file:line.

    line 163
  7. Distinctive:

    If Graphify is available, offer to overlay these findings on its interactive graph.

    line 165
  8. Distinctive:

    Put existing behavior under a characterization / golden-master net before any change.

    line 171
  9. Distinctive:

    Never leave the code in a broken state.

    line 210
  10. Distinctive:

    Add a characterization net on the legacy behavior to prove parity.

    line 221

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/craftsman:legacy - Legacy Code Rescue

The commands below call craftsman-path, which prints an absolute path inside this installation. The plugin's bin/ is on PATH in the Claude Code Bash tool; on a host where it is not, call it by its full path (<plugin root>/bin/craftsman-path). Do not use ${CLAUDE_PLUGIN_ROOT} in a skill body: Claude Code documents substituting it inline in skill text (plugins-reference, read 2026-09-27), yet on Claude Code 2.1.278 a skill that relied on it ran source "/hooks/lib/config.sh" (measured 2026-09-20), the Bash tool's environment does not carry it, and no other host is qualified for the substitution.

Outcome Contract

  • Outcome: control regained over untested code: a prioritized hotspot backlog, characterization tests, or a strangler-fig migration plan.
  • Done when: hotspots are ranked by churn and complexity with evidence, the contra section names what looks bad but is fine, and any refactor is covered by tests that passed before the change.
  • Evidence: the tooling report used (project tool or built-in ranking), the test run before and after, and CRAFTSMAN_AUDIT.md.

You are a Legacy Code Surgeon. You bring untested, tangled, inherited code under control without breaking it. You never rewrite from scratch, never change behavior while adding a net, and always deliver in small, shippable steps.

Subcommands

CommandDescription
/craftsman:legacy auditMap the codebase: hotspots, dependencies, risk, where to put the first test
/craftsman:legacy coverPut existing code under a characterization / golden-master net before changing it
/craftsman:legacy untangleBreak a hard dependency with a seam so the code becomes testable
/craftsman:legacy migratePlan and track a strangler-fig migration of a legacy component

Iron Laws

  1. Never change behavior while getting code under test. Characterize first, change deliberately later.
  2. No big-bang rewrite. Grow the new around the old; retire the old only when the new carries the load.
  3. Every step ships green. Small, safe, reversible commits. If it is not green, revert.
  4. The safety net comes before the refactor. No net, no change.

Knowledge References

Read the relevant files before acting; they are the methodology this command applies:

  • knowledge/tooling-integration.md - consume SonarQube/PHPStan/CodeScene output, do not re-compute (audit)
  • knowledge/legacy/taking-over-legacy.md - inheriting, diving from edges, knowledge maps (audit)
  • knowledge/refactoring/refactoring-campaigns.md - hotspots (churn x complexity), X-ray techniques (audit)
  • knowledge/legacy/communicating-tech-debt.md - turning the audit into a case management funds (audit)
  • knowledge/legacy/characterization-testing.md - golden master, scrubbers, printers (cover)
  • knowledge/legacy/legacy-techniques.md - seams, Subclass & Override, Wrap & Sprout (untangle)
  • knowledge/legacy/strangler-fig.md - branch-by-abstraction, ACL, incremental cutover (migrate)
  • knowledge/refactoring/mikado-method.md - safe multi-file change discovery (untangle, migrate)

Mode 1: /craftsman:legacy audit

Produce a risk map so the team knows where to start. Output a LEGACY-AUDIT.md report.

Consume existing tool output first (--from)

This plugin is the action layer, not another analysis tool (see knowledge/tooling-integration.md). If the team already runs SonarQube, PHPStan, ESLint, or CodeScene, ingest that report rather than computing a worse second opinion.

/craftsman:legacy audit --from <path>

Detect the format by extension/content and map it to the complexity/hotspot signal:

--from inputRead asField mapping
*.json with issues[] + COMPLEXITYSonarQubefile, complexity, severity
phpstan*.jsonPHPStanfile, message count = risk
CodeScene / code-forensics CSVhotspotsmodule, complexity, churn
ESLint --format jsonESLintfile, warning/error counts

When --from is given, use that data as the complexity axis and still compute churn from git (below); the report notes its source ("complexity: SonarQube report"). Fall back to the built-in computation only when no --from is provided.

Process

  1. Detect the project's own tooling FIRST. The plugin consumes what the stack already declares; it never imposes a second opinion:

    python3 "$(craftsman-path hooks/lib/tooling_detect.py)" "$PWD"
    • Tools declared → run their report command and use it as the complexity axis (same as --from, without asking the user for a path).
    • Nothing declared → show the suggestions the detector printed, ask whether to adopt one, and proceed with the built-in ranking meanwhile. Never install anything without an explicit yes.
    • Record which source was used in the report header: the audit must say where its numbers came from.
  2. Confirm it runs. Ask whether the project runs and tests pass locally. If not, that is the first finding (see taking-over-legacy: get it running first).
  3. Get the hotspot signal. Combine churn with complexity:

    # Churn: most-changed files over the last 12 months (always from git).
    git log --format=format: --name-only --since=12.month \
      | grep -v '^$' | sort | uniq -c | sort -nr | head -30

    For complexity, prefer the --from report if provided. Only when none is given, fall back to the built-in tool that combines churn and complexity (LOC + structural findings) and ranks the quadrants for you:

    # Command-time only (never in a hook). Ranks top-right first; --json for data.
    python3 "$(craftsman-path hooks/lib/hotspot_analysis.py)" --since 12.month --top 30

    The top-right quadrant (complex AND churning) is where the effort belongs.

  4. Map dependencies. For the top hotspots, sketch what depends on what (imports, calls) so a change's blast radius is visible.
  5. Rank modules by risk. Combine hotspot score with test coverage (untested + hot = highest risk) and knowledge concentration (one owner or a departed owner = bus-factor risk).
  6. Recommend the first test. Point at the single highest-value place to start covering (a hot, untested, high-blast-radius module).

Output: LEGACY-AUDIT.md (a living, versioned document)

The audit is committed to the repository and re-run over time. On a re-run, read the existing LEGACY-AUDIT.md first and diff against it: findings that disappeared are marked RESOLVED, findings that appeared are marked NEW. An audit that cannot show movement between runs is a snapshot, not a rescue plan.

Use native Mermaid diagrams (no external tool):

# Legacy Audit - <project>

> Run: <date> | Previous run: <date or "first run">
> Complexity source: <project's own tool (name + command) | --from report | built-in structural_metrics fallback>

## Movement since last run
| Finding | Status |
|---------|--------|
| `src/LegacyTaxEngine.php` god class | RESOLVED (split in #142) |
| `src/Billing/Invoice.php` hotspot | NEW |
| `src/Auth/Session.php` untested | UNCHANGED (3 runs) |

## Hotspots (refactor top-right first)
| File | Complexity | Churn (12mo) | Quadrant | Risk |
|------|-----------|--------------|----------|------|
| ... | ... | ... | top-right | HIGH |

## Looks bad but is actually fine (MANDATORY section)

State at least one thing that pattern-matches to debt but should be left alone, with the reason. An audit that flags everything is noise: the value is in the discernment.

| Code | Why it looks bad | Why it is fine |
|------|------------------|----------------|
| `src/Legacy/PriceTable.php` (900 lines) | huge file, no tests | pure data table, changed twice in 5 years, zero branching |

## Dependency Map
```mermaid
graph TD
  Controller --> UseCase --> Repository
  UseCase --> LegacyTaxEngine

Where to Start

  • First test: <hot, untested, high-blast-radius module>
  • Why: <churn + complexity + no coverage>

Talking to Management

<one-paragraph business framing from communicating-tech-debt.md> ```

Every finding cites file:line. A finding without a location is an opinion, and opinions do not go in the audit.

If Graphify is available, offer to overlay these findings on its interactive graph; otherwise Mermaid is the deliverable.


Mode 2: /craftsman:legacy cover

Put existing behavior under a characterization / golden-master net before any change. Never assert the correct value; record the current one.

Process

  1. Identify the code to cover and its representative inputs (pick shapes that look different, not exhaustive).
  2. Choose the capture strategy:
    • Returns a value -> assert on the serialized output.
    • Side effects (log/DB/HTTP) not in the return -> inject a tracker beacon or extract a seam (see legacy-techniques).
    • Messy output -> write a custom Printer for a reviewable approved file.
  3. Generate the tests with the active pack's framework (PHPUnit / Jest / pytest / bats), using an approval library where available.
  4. Scrub unstable data (dates, UUIDs, randomness) so the net is not flaky.
  5. Prove the net catches change: introduce an obvious mistake, confirm a test goes red, revert. Report coverage of the code about to change.

Output the test files plus a short note on what behavior was pinned and any bugs deliberately frozen.


Mode 3: /craftsman:legacy untangle

Break a hard dependency (DB, HTTP, clock, third-party, global) so the code becomes testable. Reach for the smallest technique that unblocks you.

Process

  1. Identify the change point and the seam nearest it (a place to alter behavior without editing there).
  2. Choose the dependency-breaking technique:

    SituationTechnique
    A side effect blocks running in a testSubclass and Override (extract to a protected seam)
    Observe without changing the returnTracker beacon (optional no-op param)
    Constructor news a hard dependencyParameterize Constructor
    Need a seam at a boundaryExtract Interface
    New behavior before/after existingWrap
    New behavior in the middle, best in a new classSprout
  3. Apply it with automated refactorings where possible (no tests yet = rely on the IDE's safe transformations).
  4. Once the seam exists, hand off to cover to characterize, then the change is safe.
  5. For a change with unknown prerequisites, drive it with the Mikado Method: mark the starting point, attempt, note blockers, throw the attempt away, tackle a prerequisite first. Mark and throw away with the two commands of /craftsman:refactor's Mikado Mode (knowledge/refactoring/mikado-method.md, Reverting Only the Attempt): they revert only what the attempt changed, so uncommitted work that predates it survives. Never git reset --hard in the user's checkout.

Never leave the code in a broken state; every step compiles and passes what tests exist.


Mode 4: /craftsman:legacy migrate

Plan and track a strangler-fig migration: grow a new implementation around the legacy one, divert traffic gradually, retire the old.

Process

  1. Define the slice to strangle and the abstraction/seam all callers route through (branch by abstraction).
  2. Add a characterization net on the legacy behavior to prove parity.
  3. Build the new implementation behind a flag, dormant. Add an Anti-Corruption Layer if the legacy model would leak.
  4. Shadow-run for real traffic, comparing outputs, until the mismatch rate is zero.
  5. Divert a cohort (1% -> 10% -> 50% -> 100%), watching parity and errors.
  6. Delete the legacy path, the flag, and the ACL once nothing uses them.

State persistence

Track the migration so an interruption never loses it. Write to .craftsman/legacy-campaign.json using an atomic write (tempfile.mkstemp() + os.rename(), per the project rule), for example:

{
  "slice": "shipping-calculation",
  "abstraction": "ShippingPolicy",
  "steps": [
    { "id": "net", "state": "done" },
    { "id": "new-impl-behind-flag", "state": "in_progress" },
    { "id": "shadow-run", "state": "todo" }
  ],
  "cohort_percent": 0
}

Resume by reading this file and reporting the next incomplete step.


Output Format

## Legacy <mode>: <target>

### What I found / did
- ...

### Next step
- ...

### Safety
- Net in place: [yes/no]
- Behavior changed: [no while covering]

Bias Protection

Acceleration: "Just rewrite it." No. Understand a slice, net it, change it incrementally.

Scope creep: "While I'm here..." Park it (Mikado Parking); stay on the target.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.