Enforces deadlines on code TODO comments
Description
This command-line program scans files for TODO / FIXME comments and fails your CI build if any:
- have an expired deadline (
by:tag is a date in the past) - are too old (
from:tag older than staleness threshold - default 90 days) - have invalid or missing tags
Give your TODO comments a deadline or created date like so:
// TODO (by:2025-09-25) add logging
// ^^^^^^^^^^^^^^^ deadline
# FIXME (from:2026-01-01) refactor these tests
// ^^^^^^^^^^^^^^^^^ created date
/* TODO (by:2028-01)
* rewrite it in rust
*/
Then, in your CI build, todo-or-else will fail when TODOs go overdue:
$ todo-or-else scan ./src ./lib
TODO SCAN RESULTS
src/components/User.tsx (2 items)
45:0 ⚠ DEADLINE EXPIRED: 2025-09-25
TODO (by:2025-09-25) add logging
30:4 ⚠ TOO OLD: 2026-01-01
# FIXME (from:2026-01-01) refactor these tests
────────────────────────────────────────────────────────────────────────────────
Scanned 104 files • Found 2 issues • 15 TODOs
✨ Done in 42ms
Todo or else is written in Go for portability and performance, and uses Tree Sitter to parse code fast and accurately. No Regex guessing here.
Why?
Developers like to leave TODO and FIXME comments but never go back to actually complete the work.
Put this in your CI pipeline (example: CircleCI, Github Actions workflows) and builds will fail if a TODO goes out of date.
This creates a way you can be flexible in the short term but confident that things will be revisited.
Languages supported
✅ CSS ☑️ LESS* ✅ TypeScript/TSX
✅ Dockerfile ✅ Python
✅ Golang ☑️ SASS/SCSS*
✅ JavaScript/JSX ✅ Shell
*= beta support
(Need more? Consider raising an issue)
TODO format
- TODO comments must have
TODOorFIXME(case-insensitive) - then follows a parenthesised list of "tags"
- tags are comma separated
key:valuepairs - then follows the task itself
For example
TODO (by:2027-03, owner:Fran) do something
Date formats
| Format | Meaning |
|---|---|
TODO (by:2025-09-25) |
Deadline: exact date |
TODO (by:2025-09) |
Deadline: last day of month |
TODO (from:2025-01-15) |
Created date (checked for staleness) |
TODOs must have either a by: (deadline) or from: (created date) tag.
Installation
Homebrew (macOS/Linux)
brew install jbreckmckye/formulae/todo-or-else
Download binary
Download from GitHub Releases.
Usage
Scan (CI enforcement)
Scans directories for TODOs and exits with error if any are invalid or expired:
$ todo-or-else scan <DIRS>
FLAGS --stale-age INT Days until a TODO with a from: tag is considered stale (default: 90)
It uses GoCodeWalker to apply .gitignore rules.
Example:
$ todo-or-else scan .
TODO SCAN RESULTS
src/components/User.tsx (2 items)
30:4 ✗ TAG VALUES: invalid deadline, must be YYYY-MM-DD or YYYY-MM
// TODO (by:soon) add logging
45:8 ⚠ DEADLINE EXPIRED: 2025-01-15
// FIXME (by:2025-01-15) refactor this
────────────────────────────────────────────────────────────────────────────────
Scanned 104 files • Found 2 issues • 15 TODOs
✨ Done in 42ms
List (view TODOs)
Lists all TODOs without enforcement:
$ todo-or-else list <DIRS>
Example:
$ todo-or-else list src
TODOS
internal/core/scan.go (1 items)
15:4 // TODO (by:2026-03-01) add logging
internal/parser/parse.go (2 items)
56:8 // FIXME (2026-06) refactor tests
128:4 // TODO (from:2025-01-01) clean this up
✨ Done in 28ms
Common patterns
# Scan files in src and lib directories todo-or-else scan ./src ./lib # List all TODOs in current directory todo-or-else list . # Mark TODOs as stale after 30 days (instead of default 90) todo-or-else scan ./src --stale-age 30
FAQ
How stable is this?
It's tested, but in Beta. Please report any bugs you think you've seen.
I want support for another language!
Consider raising a pull request to add a new language parser.
What stops me just delaying indefinitely?
What stops you deleting your whole test suite, stealing the company credit card and going on a bender to Vegas?
You still need some discipline, but at least with this, you can use TODO messages knowing they won't be forgotten.
How fast is it?
Pretty fast. On up-to-date machines it can go through a few thousand source files in just a couple of seconds. The underlying parser (Tree Sitter) is written in C.
