npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ianlewis/todos

v0.13.0

Published

Parse TODO and FIXME comments from code

Readme

todos

tests Codecov Go Report Card FOSSA Status OpenSSF Scorecard SLSA 3

todos is a fast unixy CLI tool that searches for TODO comments in code and prints them in various formats.

See the FAQ for more info on the philosophy behind the project.

Features

Installation

todos can be installed via multiple methods.

Install pre-built binaries

Download the slsa-verifier and verify it's checksum:

curl -sSLo slsa-verifier https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64 && \
echo "1c9c0d6a272063f3def6d233fa3372adbaff1f5a3480611a07c744e73246b62d  slsa-verifier" | sha256sum -c - && \
chmod +x slsa-verifier

Download and verify the todos CLI binary and verify it's provenance:

curl -sSLo todos https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64 && \
curl -sSLo todos.intoto.jsonl https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64.intoto.jsonl && \
./slsa-verifier verify-artifact todos --provenance-path todos.intoto.jsonl --source-uri github.com/ianlewis/todos --source-tag v0.13.0 && \
chmod +x todos && \
cp todos ~/bin/

Install using npm

Install todos by installing the @ianlewis/todos package from npm:

npm install -g @ianlewis/todos

Verify the package signature:

npm audit signatures

Docker image

Download and run todos with Docker. You should use a specific version tag:

docker run --rm -t -v $(pwd):/src ghcr.io/ianlewis/todos:v0.13.0 /src

Verify the image attestation using cosign:

cosign verify-attestation \
  --type slsaprovenance \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
  --certificate-github-workflow-repository "ianlewis/todos" \
  --certificate-github-workflow-ref "refs/tags/v0.13.0" \
  ghcr.io/ianlewis/todos:v0.13.0

Install from source

If you already have Go 1.20+ you can install the latest version using go install:

go install github.com/ianlewis/todos/cmd/todos

Install as a Go tool dependency

You can also install todos from source as a Go tool dependency.

go get -tool github.com/ianlewis/todos/cmd/todos

This will allow you to use todos in your project using the go tool command.

go tool github.com/ianlewis/todos/cmd/todos

Be aware though that there are a few downsides to using the Go tools approach.

  • This will compile todos locally and using your local Go version.
  • The dependencies used to compile todos may be different than those used to compile its releases and thus is not guaranteed to work.
  • It allows installation from the main branch, which may not be stable.
  • It's slower than binary installation.

Usage

Simply running todos will search TODO comments starting in the current directory. By default it ignores files that are in "VCS" directories (such as.git or .hg) and vendored code (such as node_modules, vendor, and third_party).

Here is an example running in a checkout of the Kubernetes codebase.

kubernetes$ todos
build/common.sh:346:# TODO: remove when 17.06.0 is not relevant anymore
build/lib/release.sh:148:# TODO: Docker images here
cluster/addons/addon-manager/kube-addons.sh:233:# TODO: Remove the first command in future release.
cluster/addons/calico-policy-controller/ipamblock-crd.yaml:41:# TODO: This nullable is manually added in. We should update controller-gen
cluster/addons/dns/kube-dns/kube-dns.yaml.base:119:# TODO: Set memory limits when we've profiled the container for large
cluster/addons/dns/kube-dns/kube-dns.yaml.in:119:# TODO: Set memory limits when we've profiled the container for large
cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml:120:# TODO(random-liu): Remove this after cri container runtime rolls out.
cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml:244:# TODO(random-liu): Keep this for compatibility, remove this after
cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml:345:# TODO(instrumentation): Reconsider this workaround later.
cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml:135:# TODO(random-liu): Remove this after cri container runtime rolls out.
cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml:259:# TODO(random-liu): Keep this for compatibility, remove this after
cluster/addons/fluentd-gcp/fluentd-gcp-configmap.yaml:362:# TODO(instrumentation): Reconsider this workaround later.
...

Running on sub-directories or files

You can run todos on sub-directories or individual files by passing them on the command line.

kubernetes$ todos hack/ Makefile
hack/e2e-internal/e2e-cluster-size.sh:32:#TODO(colhom): spec and implement federated version of this
hack/ginkgo-e2e.sh:118:# TODO(kubernetes/test-infra#3330): Allow NODE_INSTANCE_GROUP to be
hack/lib/golang.sh:456:# TODO: This symlink should be relative.
hack/lib/protoc.sh:119:# TODO: switch to universal binary when updating to 3.20+
hack/lib/util.sh:337:# TODO(lavalamp): Simplify this by moving pkg/api/v1 and splitting pkg/api,
hack/lib/version.sh:74:# TODO: We continue calling this "git version" because so many
hack/make-rules/test.sh:61:# TODO: This timeout should really be lower, this is a *long* time to test one
hack/module-graph.sh:19:# TODO: Containerize the script to remove dependency issues with go mod and dot.
hack/update-codegen.sh:420:# TODO: it might be better in the long term to make peer-types explicit in the
hack/verify-api-groups.sh:96:# TODO: Remove this package completely and from this list
hack/verify-e2e-test-ownership.sh:20:# TODO: these two can be dropped if KubeDescribe is gone from codebase
hack/verify-external-dependencies-version.sh:39:# TODO: revert sed hack when zetigeist respects CLICOLOR/ttys
hack/verify-licenses.sh:101:# TODO: Remove this workaround check once PR https://github.com/google/go-licenses/pull/110 is merged
Makefile:313:# TODO(thockin): Remove this in v1.29.
Makefile:504:#TODO: make EXCLUDE_TARGET auto-generated when there are other files in cmd/

Running in GitHub Actions

If run as part of a GitHub action todos will function much like a linter and output GitHub workflow commands which will add check comments to PRs.

kubernetes$ todos -o github Makefile
::warning file=Makefile,line=313::# TODO(thockin): Remove this in v1.29.
::warning file=Makefile,line=504::#TODO: make EXCLUDE_TARGET auto-generated when there are other files in cmd/

An example workflow might look like the following. todos will output GitHub Actions workflow commands by default when running on GitHub Actions:

on:
    pull_request:
        branches: [main]
    workflow_dispatch:

permissions: {}

jobs:
    todos:
        runs-on: ubuntu-latest
        permissions:
            contents: read
        steps:
            - uses: actions/checkout@v3
            - uses: slsa-framework/slsa-verifier/actions/[email protected]
            - name: install todos
              run: |
                  set -euo pipefail

                  curl -sSLo todos \
                    https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64 && \
                  curl -sSLo todos.intoto.jsonl \
                    https://github.com/ianlewis/todos/releases/download/v0.13.0/todos-linux-amd64.intoto.jsonl && \
                  slsa-verifier verify-artifact todos \
                    --provenance-path todos.intoto.jsonl \
                    --source-uri github.com/ianlewis/todos \
                    --source-tag v0.13.0 && \
                  rm -f slsa-verifier && \
                  chmod +x todos

            - name: run todos
              run: |
                  ./todos .

Outputting JSON

todos can produce output in JSON format for more complicated processing.

kubernetes$ todos -o json
{"path":"build/common.sh","type":"TODO","text":"# TODO: remove when 17.06.0 is not relevant anymore","label":"","message":"remove when 17.06.0 is not relevant anymore","line":346,"comment_line":346}
{"path":"build/lib/release.sh","type":"TODO","text":"# TODO: Docker images here","label":"","message":"Docker images here","line":148,"comment_line":148}
{"path":"cluster/addons/addon-manager/kube-addons.sh","type":"TODO","text":"# TODO: Remove the first command in future release.","label":"","message":"Remove the first command in future release.","line":233,"comment_line":233}
{"path":"cluster/addons/calico-policy-controller/ipamblock-crd.yaml","type":"TODO","text":"# TODO: This nullable is manually added in. We should update controller-gen","label":"","message":"This nullable is manually added in. We should update controller-gen","line":41,"comment_line":41}
{"path":"cluster/addons/dns/kube-dns/kube-dns.yaml.base","type":"TODO","text":"# TODO: Set memory limits when we've profiled the container for large","label":"","message":"Set memory limits when we've profiled the container for large","line":119,"comment_line":119}
{"path":"cluster/addons/dns/kube-dns/kube-dns.yaml.in","type":"TODO","text":"# TODO: Set memory limits when we've profiled the container for large","label":"","message":"Set memory limits when we've profiled the container for large","line":119,"comment_line":119}
{"path":"cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml","type":"TODO","text":"# TODO(random-liu): Remove this after cri container runtime rolls out.","label":"random-liu","message":"Remove this after cri container runtime rolls out.","line":120,"comment_line":120}
{"path":"cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml","type":"TODO","text":"# TODO(random-liu): Keep this for compatibility, remove this after","label":"random-liu","message":"Keep this for compatibility, remove this after","line":244,"comment_line":244}
{"path":"cluster/addons/fluentd-gcp/fluentd-gcp-configmap-old.yaml","type":"TODO","text":"# TODO(instrumentation): Reconsider this workaround later.","label":"instrumentation","message":"Reconsider this workaround later.","line":345,"comment_line":345}
...
kubernetes$ # Get all the unique files with TODOs that Tim Hockin owns.
kubernetes$ todos -o json | jq -r '. | select(.label = "thockin") | .path' | uniq

Supported Languages

See SUPPORTED_LANGUAGES.md.

TODO comment format

"TODO" comments are comments in code that mark a task that is intended to be done in the future.

For example:

// TODO(label): message text

TODO comment type variants

There a few variants of this type of comment that are in wide use.

  • TODO: A general TODO comment indicating something that is to be done in the future.
  • FIXME: Something that is broken that needs to be fixed in the code.
  • BUG: A bug in the code that needs to be fixed.
  • HACK: This code is a "hack"; a hard to understand or brittle piece of code. It could use a cleanup.
  • XXX: Danger! Similar to "HACK". Modifying this code is dangerous. It
  • COMBAK: Something you should "come back" to.

TODO comment examples

TODO comments can include some optional metadata. Here are some examples:

  • A naked TODO comment.

    // TODO
  • A TODO comment with an explanation message

    // TODO: Do something.
  • A TODO comment with a linked bug or issue and optional message

    // TODO(github.com/ianlewis/todos/issues/8): Do something.
  • A TODO comment with a username and optional message. This type is discouraged as it links the issue to a specific developer but can be helpful temporarily when making changes to a PR. Linking to issues is recommended for permanent comments.

    // TODO(ianlewis): Do something.

Use Cases

Tracking TODOs in code can help you have a cleaner and healthier code base. Here are some basic use cases.

Finding TODOs in your code

You can use the [todos CLI] to find TODO comments in your code and print them out. Running it will search the directory tree starting at the current directory by default.

$ todos
main.go:27:// TODO(#123): Return a proper exit code.
main.go:28:// TODO(ianlewis): Implement the main method.

In order for the comments to be more easily parsed keep in mind the following:

  • Spaces between the comment start and 'TODO' is optional (e.g. //TODO: some comment)
  • TODOs should have a colon if a message is present so it can be distinguished from normal comments.
  • TODOs can be prefixed with @ (e.g. // @TODO: comment)
  • Comments can be on the same line with other code (e.g. x = f() // TODO: call f
  • Line comment start sequences can be repeated (e.g. //// TODO: some comment)
  • Only the single line where the TODO occurs is printed for multi-line comments.
  • TODO,FIXME,BUG,HACK,XXX,COMBAK are supported by default. You can change this with the --todo-types flag.

See the [todos CLI] documentation for more info.

Documenting tasks

You can use the output of todos to create documentation of tasks.

For example, this creates a simple markdown document:

$ (
    echo "# TODOs" && \
    echo && \
    todos --exclude-dir .venv --output json | \
        jq -r 'if (.label | startswith("#")) then "- [ ] \(.label) \(.message)" else empty end' | \
        uniq
) > todos.md

$ cat todos.md
# TODOs

- [ ] #1546 Support @moduledoc
- [ ] #96 Use a *Config
- [ ] #96 Use []*Comment and go-cmp
- [ ] #1627 Support OCaml nested comments.
- [ ] #1540 Read this closed string as a comment.
- [ ] #1545 Generate Go code rather than loading YAML at runtime.

Re-open prematurely closed issues

Sometimes issues get closed before all of the relevant code is updated. You can use todos to re-open issues where TODO comments that reference the issue still exist in the code.

// TODO(#123): Still needs work.

See ianlewis/todo-issue-reopener for more information.

Related projects

FAQ

Why use this?

Tracking TODOs in code can help you have a cleaner and healthier code base.

  1. It can help you realize when issues you thought were complete actually require some additional work (See ianlewis/todo-issue-reopener).
  2. It makes it easier for contributors to find areas of the code that need work.
  3. It makes it easier for contributors to find the relevant code for an issue.

Why not just use grep or rg?

grep and rg are amazing and very fast tools. However, there are a few reasons why you might use todos.

  1. grep and rg don't have much knowledge of code and languages so it's difficult to differentiate between comments and code. todos will ignore matches in code and only prints TODOs found it comments. It also ignores matches that occur in strings.
  2. grep doesn't know about repository structure. It doesn't have inherent knowledge of VCS directories (e.g. .git) or vendored dependencies. It can't make use of .gitignore or other hints.
  3. todos can output JSON with parsed values from the TODOs. This gives users an easy way to search for TODOs with their username, or with a specific issue number.

Contributing

See CONTRIBUTING.md for contributor documentation.