Code Archaeology skill for Claude Code

Learn why code exists before you delete it. Claude finds the commit that actually introduced a behavior, not the last formatter run, using blame that ignores whitespace and moves plus pickaxe and line-range history. It reads the PR discussion, linked issues and ADRs, quotes the original reason, checks whether that reason still holds against today's code, dependencies and data, and ends with a provenance note and a recommendation backed by evidence.

  • namecode-archaeology
  • size136 lines · ≈1,650 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Finds out why code exists before it is changed or deleted, by tracing its origin with git blame (ignoring whitespace, moves, and formatting commits), git log -S, -G, -L and --follow, the pull requests and issues behind each commit, ADRs, changelogs, and runtime usage evidence, then writes a short provenance note with a keep, change, or delete recommendation. Use when the user asks why something is done this way, whether code is still needed, who added it, what breaks if it is removed, or before touching weird-looking code.

Try asking

  • Why does this function sleep for 7 seconds before retrying? Find out where it came from
  • Is this weird special case for customer 4021 still needed, or can we delete it?
  • Who added this config flag and what was it for?

Use it when

  • Code looks wrong or odd and you are about to change it
  • You want to delete something but do not know why it was added
  • Blame points at a refactor or formatting commit
  • A reviewer asks for the history behind a decision

Skip it when

  • You already know the code is unused and need to remove it safely — use dead-code-removal instead
  • You need to rewrite or repair git history itself — use git-history-surgery instead

How to check the result

The note names the introducing commit and PR, quotes the stated reason, and shows a concrete check of whether that reason still applies today.

The common mistake it prevents

Running plain git blame, landing on a bulk formatting or file-move commit, and attributing the code to the wrong author and reason.

~/.claude/skills/code-archaeology/SKILL.md

--- name: code-archaeology description: Finds out why code exists before it is changed or deleted, by tracing its origin with git blame (ignoring whitespace, moves, and formatting… license: MIT ---

An archaeology answer is done when it names the commit that introduced the behavior, the reason (from a PR, issue, ADR, or commit message, quoted), whether that reason still holds today, and a recommendation with the evidence for it. “Probably legacy” is not an answer; neither is the last commit that reformatted the line.

Workflow

- [ ] 1. Pin the target: exact lines, symbol, config key, or behavior
- [ ] 2. Find the introducing commit (not the last toucher)
- [ ] 3. Read the context: full commit, PR discussion, linked issues, ADRs
- [ ] 4. Check whether the reason still holds (code, tests, data, traffic)
- [ ] 5. Recommend keep / change / delete, with risk and verification plan

1. Pin the target

Write the question precisely: “Why does retryPayment() sleep 7 seconds before the second attempt (src/billing/retry.ts:48)?” Note the symbol names, string literals, and config keys involved; they are your search terms.

2. Find the introducing commit

Start with blame that sees through noise:

git blame -w -C -C -M -L 40,60 -- src/billing/retry.ts
git blame --ignore-revs-file .git-blame-ignore-revs -L 40,60 -- src/billing/retry.ts
  • -w ignores whitespace; -M detects moved lines within a file; -C -C detects lines copied or moved from other files in the same or any commit.
  • If the repo has a .git-blame-ignore-revs (bulk formatting commits), use it; set it permanently with git config blame.ignoreRevsFile .git-blame-ignore-revs.
  • If blame lands on a refactor, rename, or formatting commit, re-blame its parent: git blame -w -C -C <sha>^ -L 40,60 -- <old-path>.

When blame keeps hitting refactors, search history by content instead:

QuestionCommand
When did this string/symbol appear or disappear?git log -S'sleep(7000)' --oneline -- src/
When did lines matching a regex change?`git log -G’retry(Count
Full history of one functiongit log -L :retryPayment:src/billing/retry.ts
History of a line rangegit log -L 40,60:src/billing/retry.ts
History across renamesgit log --follow --oneline -- src/billing/retry.ts
Who touched this area most (expertise)git shortlog -sn -- src/billing/
When did a file get deleted / where did it gogit log --diff-filter=D --summary -- '**/oldname.ts'

-S finds commits that change the number of occurrences (introductions and removals); -G finds any commit whose diff lines match. Use --all to include other branches, and --reverse to see the earliest first.

3. Read the context

git show --stat <sha>                 # the whole change, not just your line
git show <sha> -- src/billing/        # what else changed with it
gh pr list --state merged --search "<sha>" --json number,title,url
gh api repos/{owner}/{repo}/commits/<sha>/pulls --jq '.[].html_url'
gh pr view <n> --comments             # review discussion often holds the real reason

Then follow links: issue numbers in the commit or PR (#123, JIRA-456), incident or postmortem references, ADRs (docs/adr/, docs/decisions/), CHANGELOG entries, and code comments near the line (git log -S on a comment’s text finds when it was written).

Record quotes, not paraphrases. A commit message like “fix” is weak evidence; a PR description saying “provider rate-limits retries within 5 s (see incident 2023-04-11)” is strong.

Squash-merged repos: the PR is the unit of history; the squash commit body often lists the original commit messages. Rebased or vendored code: look for “imported from” notes or an upstream repo and continue there.

4. Does the reason still hold?

Reason typeHow to check today
Workaround for a dependency bugFind the upstream issue; is it fixed in the version we use? (npm ls, lockfile)
External constraint (rate limit, API quirk)Current provider docs; integration tests; ask the owner
Data shape (legacy rows, old clients)Query production-like data: SELECT count(*) WHERE legacy_flag ; client version metrics
Feature flag or experimentFlag state in the flag service; last evaluation time
Performance fixBenchmark or trace with and without
UnknownTreat as load-bearing until proven otherwise

Usage evidence for “is anything still calling this?”: references in the repo (rg -n symbolName), other repos that depend on it, logs/metrics for the endpoint or code path, and feature-flag evaluations. Absence in one repo is not absence everywhere.

5. Recommend

FindingRecommendation
Reason documented and still trueKeep; add a comment linking the PR/issue so the next person does not repeat this
Reason gone (upstream fixed, flag at 100% for months, no traffic)Delete, behind a test or flag if risky; see dead-code-removal
Reason partly trueChange: narrow the workaround, parameterize, add a test that encodes the constraint
Reason unknown after searchKeep, add a characterization test, ask the listed owners; do not delete on a hunch

If the code survives, leave a breadcrumb at the site:

// Provider rejects retries within 5 s of a failure (PR #812, incident 2023-04-11).
// Keep >= 5000 ms unless the provider contract changes.

Gotchas

  • Blaming without -w -C -C -M usually lands on a formatter or file move, sending you to the wrong author and the wrong reason.
  • Shallow clones (CI, some containers) have truncated history: git rev-parse --is-shallow-repository; run git fetch --unshallow if true.
  • The person who wrote it may have only moved it. Check git show for a move before asking them.
  • Old code with tests that assert the odd behavior is strong evidence it is intentional; read those tests before concluding it is a bug.
  • Do not post speculation as fact in PRs; label hypotheses and show the evidence trail.

Output

**Question:** Why does retryPayment() wait 7 s before the second attempt? (src/billing/retry.ts:48)
**Introduced:** 3f2a9c1 (2023-04-12, @dkim) "Delay payment retry past provider window" via PR #812
**Reason (quoted):** "Stripe returns rate_limit when the same card is retried within 5 s; incident 2023-04-11 double-declined 300 orders."
**Still holds?** Yes — provider docs still describe per-card retry throttling; integration test `retry_respects_window` encodes it
**History:** moved from payments/legacy.ts in 9b01de4 (refactor, no behavior change); delay raised 5 s -> 7 s in 1c77e02 for clock skew
**Recommendation:** Keep. Add comment linking #812; extract 7000 to `PROVIDER_RETRY_WINDOW_MS`

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc