Skip to the content.

Setup Guide

This guide walks you through standing up the autolabel service on your own machine.

For an overview, see the README.

Prerequisites

Install

Option A — run directly with npx

No install required:

npx @glorioustephan/todoist-autolabel

npx will resolve the latest published version and run it against the .env and labels.json files in your current directory.

Option B — pin in a project

pnpm add @glorioustephan/todoist-autolabel

Then either invoke it via the project’s package scripts, or run the bin:

pnpm exec todoist-autolabel

Configure

The service reads configuration from two files in the current working directory:

npx @glorioustephan/todoist-autolabel init

init drops a starter .env and labels.json next to wherever you ran the command (refusing to overwrite existing files unless you pass --force).

If you’d rather hand-roll them, the templates are described below.

.env

Copy the template and fill in your credentials:

cp node_modules/@glorioustephan/todoist-autolabel/env.example .env

The only required variables are:

TODOIST_API_TOKEN=your_todoist_token
ANTHROPIC_API_KEY=your_anthropic_key

Everything else has a sensible default — see the full env reference below.

labels.json

This is your Todoist label taxonomy. Every entry must already exist as a label in Todoist.

A starting point (red/grey themed to match Todoist’s palette) is published with the package as labels.example.json:

{
  "labels": [
    { "name": "urgent",   "color": "red" },
    { "name": "waiting",  "color": "grey" },
    { "name": "errands",  "color": "red" },
    { "name": "work",     "color": "berry_red" },
    { "name": "personal", "color": "grey" }
  ]
}

Save your taxonomy as labels.json in the same directory as .env — or anywhere you like, and tell the CLI where to find it:

# Per-invocation:
npx @glorioustephan/todoist-autolabel --labels ./taxonomies/work.json

# Or in .env:
LABELS_PATH=./taxonomies/work.json

The color values use Todoist’s named palette (e.g. red, berry_red, grey, charcoal, taupe, sky_blue, …).

Get your API tokens

Todoist

  1. Open Todoist → Settings → IntegrationsDeveloper tab.
  2. Copy the API token at the bottom of the page.

Anthropic

  1. Sign in at https://console.anthropic.com/.
  2. Go to API Keys and create a new key.
  3. Make sure your account has credits / a billing method attached.

First run

npx @glorioustephan/todoist-autolabel

On boot the service will:

  1. Validate .env and connect to the Anthropic + Todoist APIs.
  2. Resolve your Inbox project (walking pagination if necessary).
  3. Open / create the SQLite DB at DB_PATH.
  4. Begin its sync loop — every POLL_INTERVAL_MS it pulls Inbox tasks without labels and classifies them.

Stop it with Ctrl+C. The shutdown handler closes the DB cleanly.

Environment variables reference

Variable Required Default Description
TODOIST_API_TOKEN yes Todoist API token
ANTHROPIC_API_KEY yes Anthropic API key
ANTHROPIC_MODEL no claude-haiku-4-5-20251001 Any Claude model with Structured Outputs support
MAX_LABELS_PER_TASK no 5 Hard cap on labels per task
POLL_INTERVAL_MS no 15000 Polling interval in ms
MAX_ERROR_LOGS no 1000 FIFO cap on error_logs
DB_PATH no <cwd>/data/todoist.db SQLite DB location
LABELS_PATH no <cwd>/labels.json Override the labels file location
LOG_LEVEL no info debug | info | warn | error
BACKFILL_ON_START no true Retry every still-unlabelled Inbox task on each service boot
BACKFILL_INTERVAL_MS no 86400000 (24h) Periodic retry sweep cadence. 0 disables.
BACKFILL_COOLDOWN_MS no 3600000 (1h) Per-task floor between successive retries

Backfill and retry sweep

A task that fails 3 classification attempts is marked failed in the local DB and the regular sync loop stops re-trying it, so a temporarily-broken API or a malformed task doesn’t burn classifier calls forever. Two safety valves bring those tasks back without manual intervention:

Both knobs use BACKFILL_COOLDOWN_MS (default 3600000 = 1h) as a per-task floor: a task that was just attempted won’t be reset, so a genuinely-unclassifiable task settles into ~1 attempt per cooldown interval rather than spinning.

To stop attempts on a perma-failing task: delete it from Todoist, or label it manually. Both make the sync loop skip it on every future pass.

Supported Claude models

Structured Outputs (and therefore this service) requires Claude Haiku 4.5+, Sonnet 4.5+, or Opus 4+. Earlier models will fail at the API.

Model Speed Cost (in/out per 1M) Best for
claude-haiku-4-5-20251001 Fastest ~$1 / ~$5 Default — cheapest and fastest
claude-sonnet-4-5-20250929 Fast ~$3 / ~$15 Subtle / ambiguous taxonomies
claude-opus-4-20250514 Slower ~$15 / ~$75 Very large taxonomies

Troubleshooting

TODOIST_API_TOKEN environment variable is not set

The CLI loads .env from the current working directory, not from where the package is installed. Make sure you’re running the command from the directory that holds your .env.

Could not find Todoist Inbox project

The token does not have access to a project flagged inboxProject. Double-check the token belongs to the right account, or regenerate it from the Todoist developer settings.

Tasks aren’t being classified

  1. Make sure the tasks are in your Inbox — the service intentionally ignores other projects.
  2. Make sure the tasks have no labels yet — labelled tasks are skipped to avoid clobbering manual work.
  3. Confirm the model in ANTHROPIC_MODEL is one of the supported ones above.
  4. Re-run with LOG_LEVEL=debug for verbose output.

Database locked

Only one instance of the service should run against a given DB_PATH at a time. Stop the duplicate, or point one of them at a different DB_PATH.

Rate-limit errors from Todoist

The service inserts a 200 ms delay between writes, but if you have a lot of unlabelled tasks plus heavy other Todoist usage, raise POLL_INTERVAL_MS (e.g. to 300000 for 5 min).

Next steps