todoage
v0.1.0
Published
Scan your codebase for TODO/FIXME/HACK/XXX/BUG comments and use git blame to show how old each one is and who wrote it. Flags tech debt older than N days. CI-friendly, zero dependencies.
Maintainers
Readme
todoage
How old is your tech debt? todoage scans your codebase for
TODO / FIXME / HACK / XXX / BUG comments, then uses git blame to show
how old each one is and who wrote it — and flags anything that's been rotting
longer than your threshold.
Zero dependencies. Zero config. Read-only — it never writes to your repo.
npx todoageAGE TAG LOCATION AUTHOR TEXT
418d FIXME src/auth/session.js:71 Alice Dev refresh tokens before they expire
402d TODO src/billing/charge.js:12 Alice Dev validate the amount before charging
311d HACK src/api/proxy.ts:88 Bob Maintainer works around the upstream 1.4 bug
9d TODO src/ui/cart.tsx:140 Carol wire up the empty-cart state
summary: 4 markers · 3 older than 90dThe red rows are your stalest debt — the stuff that quietly became permanent.
Why it exists
tickgit (324★) promised exactly this — blame + age tracking for your TODOs — and then went quiet in 2020 having never shipped it. VS Code's todo-tree solves IDE visibility, but there's no small CLI that does the age + author part for a CI report or a Markdown summary.
So that's all todoage is: the missing CLI. It answers one question — which
of these TODOs has been here so long it's basically a lie? — and answers it in
a way you can drop into a CI gate.
How it works
It walks your tree (skipping .git, node_modules, .venv, dist, build
artifacts and obvious binaries), matches comment markers in real comment
contexts (//, #, /* */, <!-- -->, --, ;, leading *), and asks
git blame for the author and author-date of each matching line. Age is whole
days from the commit that introduced the line.
Markers are case-sensitive UPPER, so todomvc and fixme_helper don't
trigger false positives — only an actual // TODO does.
Not in a git repo? It still lists every marker; age and author just show as ?.
Install
npx todoage # no install, run on demand
npm i -g todoage # or install the `todoage` command globallyThere's an identical Python build too: pipx run todoage / pip install todoage
(see todoage-py). Both ports are tested
against the same vectors, so they produce byte-for-byte identical output.
Usage
todoage [path] [options]| Option | Description |
| --- | --- |
| --max-age <days\|90d> | Staleness threshold (default 90). Suffixes: d w m y (e.g. 12w, 6m, 1y). |
| --tags <list> | Comma-separated markers to scan for (default TODO,FIXME,HACK,XXX,BUG). |
| --author <substr> | Only items whose blame author contains this substring. |
| --json | Emit compact JSON instead of a table. |
| --fail-on-stale | Exit 1 if any item is stale — a one-line CI gate. |
| --no-color | Disable ANSI color. Also respects NO_COLOR. |
| -h, --help | Show help. |
| -v, --version | Print version. |
Exit codes: 0 nothing stale · 1 stale found (with --fail-on-stale) ·
2 usage error.
Examples
# fail CI if any TODO is older than a quarter
npx todoage --max-age 90d --fail-on-stale
# just the FIXMEs Alice left behind
todoage --tags FIXME --author alice
# feed a dashboard / Markdown summary
todoage --json | jq '.items[] | select(.stale)'
# scan one subtree, tighter threshold
todoage src/ --max-age 30dDesign notes
- One pure core, two runtimes.
scanLine,ageDays, andisStaleare pure functions with no I/O, clock, or git — driven by a shared input→output vectors table that the Node and Python suites both run. That's what proves the two ports agree. - Age math never touches a
Date. It's integer milliseconds → whole days, so the result is deterministic and identical across languages. - Read-only. It blames, it prints, it exits. No state, no cache, no config file, nothing written to your tree.
License
MIT
