@avelor/stale
v0.1.0
Published
Find stale TODO/FIXME markers by age. Breaks CI when technical debt sits too long.
Maintainers
Readme
stale
Find stale TODO/FIXME markers by age. Breaks CI when technical debt sits too long.

847d src/auth/middleware.js:43 HACK # bypass validation for now
312d src/api/payments.js:112 TODO handle refunds
14d tests/payments.test.js:8 test.todo handles partial refund
✖ 2 markers exceeded the age limit.The age comes from git blame. Not when the file was last touched — when that specific line was committed.
Install
npm install -g @avelor/staleRequires Node.js 18+ and git.
Usage
stale # scan using .stale.yml in current directory
stale tests/ # only scan tests/
stale --max-age 7 # override max-age for this runExit code is 0 if nothing is over the limit, 1 if anything is. Any CI pipeline understands this without extra configuration.
.stale.yml
max-age: 30
ignore:
- dist/
- "**/*.generated.*"
rules:
- paths: [src/, lib/]
tags: [TODO, FIXME, HACK]
- paths: [tests/, __tests__/]
tags: [test.todo, it.todo, test.skip, describe.skip, xit, xdescribe]
max-age: 14
ignore:
- tests/fixtures/Each rule is independent. max-age and ignore at the top level are the defaults — rules inherit them and can override.
| Field | Description |
|---|---|
| max-age | Days before a marker is considered stale |
| ignore | Glob patterns to skip. Rule-level ignore adds to the global list. |
| paths | Directories or files this rule applies to |
| tags | Strings to search for (substring match per line) |
CI / GitHub Actions
Use --format github to emit native GitHub annotations — they appear as inline errors on the PR diff.
- name: Check stale markers
run: npx @avelor/stale --format githubOutput:
::error file=src/api/payments.js,line=112::TODO is 312d old (limit: 30d) — handle refunds
::warning file=tests/payments.test.js,line=8::test.todo is 14d old (limit: 14d) — handles partial refundWarnings for markers approaching the limit. Errors for markers over it.
Options
--max-age <days> Override global max-age
--format <type> human (default), json, github
--config <path> Path to config file (default: .stale.yml)
-h, --helpJSON output
Useful for filtering or feeding into other tools.
stale --format json | jq '.[] | select(.violation)'Each entry:
{
"file": "src/api/payments.js",
"line": 112,
"tag": "TODO",
"content": "// TODO: handle refunds",
"ageDays": 312,
"maxAge": 30,
"author": "Jane Doe",
"violation": true
}How it works
stale reads your .stale.yml, walks the configured paths, and searches each file for the configured tags. For every match, it runs git blame on that line to get the commit date. Age is calculated from that date to today.
Files not tracked by git report 0 days and never trigger a violation.
License
MIT
