A reference extension for the Todoist CLI. It says hello and reports what the CLI passed to it. The point is the shape, not the feature: copy td-hello, change what it does, and you have an extension.
td extension install scottlovegrove/td-hello
td hello
td hello Scott --json
An executable named td-<name> at the root of a repository named td-<name>. That is the whole requirement. It can be written in any language, because the CLI talks to it through the process boundary rather than through an API: it spawns the executable, passes your arguments through untouched, shares its own input and output streams, and exits with whatever the extension exited with.
| Variable | What it is |
|---|---|
TD_EXTENSION |
1, so a script can tell it was launched by td |
TD_EXTENSION_NAME |
the command name it was invoked as |
TD_EXTENSION_DIR |
this extension's own directory, for bundled files |
TD_PATH |
the CLI's entry script |
TD_NODE |
the Node binary the CLI itself runs on |
TD_VERSION |
the CLI's version, for feature detection |
TD_CONFIG_DIR |
the CLI's config directory, to read |
TD_USER |
set only when --user was given before the extension name |
There is no API token in there, and there never will be. The CLI does not hand its credentials to the code it launches. If you genuinely need the raw token, run td auth token view and you will get it, explicitly, with the user's own account selection applied. Most extensions never need to: ask td for what you want instead, with --json, and you inherit its authentication, its account handling and its output conventions for free.
const { TD_NODE, TD_PATH } = process.env
const [command, prefix] = TD_NODE && TD_PATH ? [TD_NODE, [TD_PATH]] : ['td', []]
const { stdout } = await execFile(command, [...prefix, 'task', 'list', '--json'])Use both variables. On Windows the CLI is installed as a shim that cannot be spawned as a plain executable, so TD_PATH alone will not run. Falling back to td on PATH keeps the extension runnable on its own while you are writing it.
- Data to stdout, diagnostics to stderr, so
td hello --json | jqworks. - Honour
--jsonif you produce data at all. People and agents both call these. - Exit non-zero on failure. The CLI exits with your code.
- Never prompt when stdin is not a terminal. The CLI is non-interactive by design.
- Print your own
--help. Everything after the extension name reaches you untouched,--helpincluded. - Declare a version range in
td-extension.jsonif you depend on recent CLI behaviour. Failing it warns rather than refuses, so an upgrade of the CLI never silently breaks a working extension.
mkdir td-yourthing && cd td-yourthing
# write an executable file called td-yourthing
td extension install .
td yourthing
A local install is a link to your working directory, so every edit is live. When you are ready, push it to a repository called td-yourthing, add the td-extension topic, and anyone can install it by name.
MIT.