In the agency and contractor world, you get thrown into a loooooot of code bases. Onboarding and getting your bearings, I find, can often be the part with the most friction. Granted, thanks to AI, it's gotten a bit smoother. I recently saw a blog post from Ally Piechowski making the rounds on the internet. I took his process, combined it with what I was already doing, and turned it into an AI skill that produces a visual history. I want to reiterate: the commands running in the background are 90% from his blog post.
Project Breakdown
Every legacy codebase comes with a maintenance log. Nobody ever reads it, because it's not a binder on a shelf, it's buried in git log and everyone would rather just start clicking through files and vibing. That's how you end up three days into a new repo confidently refactoring the one file that's been on fire for two years, and nobody mentioned it because nobody looked.
Scoping first
Before collecting anything, the skill locates the primary source directory ( src/ , app/ , lib/) and scopes every churn and bug query to it. Run those queries against the repo root instead, and lockfiles, changelogs, and generated code dominate every list. Obviously the package lock files will have some of the highest activity, we don’t want that noise.
The commands
Vitals: age, size, and who's around
git log --reverse --format='%ad' --date=short | head -1 # first commit
git log -1 --format='%ad' --date=short # last commit
git rev-list --count HEAD # total commits
git ls-files | wc -l # tracked files
git shortlog -sn --no-merges HEAD | wc -l # all-time contributors
git shortlog -sn --no-merges --since='1 year ago' HEAD | wc -l # active contributorsEvery later verdict gets calibrated against this. "High churn" means something different on a 200-commit side project than on a 20,000-commit monster that's been running since Obama's first term.
Language mix: extensions, counted and ranked:
git ls-files | sed -n 's/.*\.\([A-Za-z0-9_]\{1,10\}\)$/\1/p' | sort | uniq -c | sort -nr
One line, and it already tells you more than the README does. Free signal for what the repo actually is before you've read a single import statement.
Churn, two windows: most-touched files, last year vs. last two months:
git log --format=format: --name-only --since="1 year ago" -- "$SRC" | sed '/^$/d' | sort | uniq -c | sort -nr
git log --format=format: --name-only --since="2 months ago" -- "$SRC" | sed '/^$/d' | sort | uniq -c | sort -nrOne window isn't enough, because churn by itself doesn't necessarily mean anything. All the stoic bros will tell you, change is morally neutral, it’s just perception. A file that churned hard over the year but has gone quiet the last two months has settled down. A file churning hard in both windows is either evolving fast or actively bleeding, and churn alone can't tell you which. That's what the next command is for
Bug-fix clusters: same shape, filtered to commits that smell like an apology:
git log -i -E --grep="fix|bug|broken" --name-only --format='' -- "$SRC" | sed '/^$/d' | sort | uniq -c | sort -nr
Cross-reference this against the churn list and you get the Danger Zone: files that change constantly and keep breaking. You know, the one that has the DO NOT TOUCH THIS comment that everyone is afraid of.
Contributors: all-time vs. six months
git shortlog -sn --no-merges HEAD
git shortlog -sn --no-merges --since="6 months ago" HEADDiffing these two commands answers the bus factor question. How is the spread of the knowledge of the codebase and are those legends still around.
Monthly velocity: commits bucketed by month, full history
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c
Charted, this stops being a number and becomes a shape. Steady rhythm: healthy. A sustained ≥40% drop: someone probably left and nobody backfilled. Spikes then silence: batch releases, not decline… don't panic over that one, it's just how some teams ship. (NOTE: Some code bases reach maturity and serve their purpose without much other than package updates… nothing wrong there)
Firefighting log: reverts, hotfixes, rollbacks, last year, with dates
git log --format='%ad %s' --date=short --since="1 year ago" | grep -iE 'revert|hotfix|emergency|rollback'
Deliberately a commit-message grep, not a git flag. What parts of the code base have had devs ugly crying on a Friday evening because the PM said deployment on Friday morning was low risk.
TODO/FIXME register:
git grep -c -iE 'TODO|FIXME|HACK|XXX' -- "$SRC" | sort -t: -k2 -nr
git grep stays fast on a big repo and respects .gitignore without being asked twice. Where this list overlaps with the churn and bug-cluster lists, that's known-broken code someone already flagged and nobody ever circled back for. The confession was in the codebase the whole time.
Lockfile staleness: last-touched date, whichever manifest actually exists
git log -1 --format='%ad (%ar)' --date=short -- package-lock.json
We’ve all been there, legacy dependency hell. Is the repo on top of it or not?
Commit timing: hour and weekday distribution, last year
git log --format='%ad' --date=format:'%H' --since="1 year ago" | sort | uniq -c
git log --format='%ad' --date=format:'%u %a' --since="1 year ago" | sort | uniq -cCross-referenced with the firefighting log, this is what separates "this team just likes late nights" from "this team is up at 2am because production is on fire again." Same data point, very different Tuesday.
The Visual Output
I’m currently building a personal React Native app, so I ran this on an example repo I’ve been studying:
:quality(80))