6 releases
| 0.2.0 | Feb 24, 2026 |
|---|---|
| 0.1.4 | Feb 21, 2026 |
| 0.1.2 | Jan 27, 2026 |
#98 in Compression
1MB
22K
SLoC
td - Todoist CLI
A fast, offline-capable command-line interface for Todoist written in Rust.
Features
- Offline-first: Local cache enables instant reads without network calls
- Sync on demand: Explicit
--syncflag ortd synccommand to fetch updates - Filter expressions: Powerful query syntax compatible with Todoist filters
- Natural language: Quick-add tasks with dates, projects, and labels
- Secure token storage: OS keyring integration (macOS Keychain, Windows Credential Manager, Linux Secret Service)
- Interactive setup: First-run wizard guides you through configuration
- Smart suggestions: "Did you mean?" hints for project and label typos
- JSON output: Machine-readable output for scripting and automation
- Shell completions: Tab completion for bash, zsh, fish, and PowerShell
Project Structure
This is a Cargo workspace with three crates:
| Crate | Description |
|---|---|
todoist-cli-rs |
CLI binary (installs as td) |
todoist-api-rs |
Todoist Sync API client library |
todoist-cache-rs |
Local cache and filter expression engine |
Installation
Homebrew (macOS/Linux)
brew install LuoAndOrder/tap/todoist-cli
Pre-built binaries
Download the latest release from GitHub Releases:
| Platform | Download |
|---|---|
| macOS (Apple Silicon) | td-aarch64-apple-darwin.tar.gz |
| macOS (Intel) | td-x86_64-apple-darwin.tar.gz |
| Linux (x64) | td-x86_64-unknown-linux-gnu.tar.gz |
| Windows (x64) | td-x86_64-pc-windows-msvc.zip |
# macOS/Linux: extract and move to PATH
tar xzf td-*.tar.gz
sudo mv td /usr/local/bin/
Cargo
cargo install todoist-cli-rs
Build from source
git clone https://github.com/LuoAndOrder/todoist-rs
cd todoist-rs
cargo build --release
The binary will be at target/release/td.
Quick Start
1. Run any command to start the setup wizard
On first run, td will guide you through setup interactively:
td list
The wizard will:
- Prompt for your API token (get it from Todoist Settings > Integrations > Developer)
- Validate the token by syncing your data
- Ask where to store the token (OS keyring, config file, or environment variable)
Manual setup (alternative)
# Option 1: Environment variable
export TODOIST_TOKEN="your-api-token"
# Option 2: Save to config
td config set token "your-api-token"
2. List your tasks
td list
td today
Sync and Caching
How the cache works
td maintains a local cache of your Todoist data at:
- macOS/Linux:
~/.cache/td/cache.json - Windows:
%LOCALAPPDATA%\td\cache.json
The cache stores tasks, projects, labels, sections, and other data locally. This enables:
- Instant reads: List and filter commands return immediately without network calls
- Offline access: View your tasks even without internet connectivity
- Reduced API usage: Only sync when you need fresh data
When to sync
The cache is not automatically updated. You control when to sync:
# Explicit sync command
td sync
# Sync before any command with --sync flag
td list --sync
td today --sync
Sync command options
# Incremental sync (default) - fast, only fetches changes
td sync
# Full sync - rebuilds cache from scratch
td sync --full
Use --full when:
- The cache seems corrupted
- You suspect data is out of sync
- After major changes in the Todoist web/mobile app
The --sync flag
Every read command supports --sync to ensure fresh data:
td list --sync # Sync then list all tasks
td today --sync # Sync then show today's agenda
td list -f "p1" --sync # Sync then filter by priority
td projects --sync # Sync then list projects
Best practice: Use --sync when you need current data, skip it for speed when working with known tasks.
Write operations
Commands that modify data (add, done, edit, delete) always communicate with the Todoist API directly. They also update the local cache to keep it consistent.
Commands
Command Aliases
Most commands have short aliases for quick access:
| Command | Alias | Description |
|---|---|---|
list |
l |
List tasks |
add |
a |
Add a task |
show |
s |
Show task details |
edit |
e |
Edit a task |
done |
d |
Complete task(s) |
delete |
rm |
Delete task(s) |
today |
t |
Today's agenda |
quick |
q |
Quick add with natural language |
projects |
p |
Manage projects |
labels |
lb |
Manage labels |
filters |
f |
Manage saved filters |
collaborators |
List project collaborators |
Task Management
# List tasks
td list # All active tasks (limit 50)
td list --all # All tasks, no limit
td list -f "today & p1" # Filter: today's priority 1 tasks
td list -p "Work" # Tasks in Work project
td list -l "urgent" # Tasks with @urgent label
td list --assigned-to me # Tasks assigned to you
td list --assigned-to "Alice" # Tasks assigned to Alice
# Show today's agenda
td today # Today's tasks + overdue
td today --no-overdue # Just today, no overdue
td today --include-upcoming 3 # Include next 3 days
# Add tasks
td add "Buy groceries"
td add "Review PR" -p "Work" -P 1 -d "tomorrow"
td add "Research topic" -l "reading" -l "later"
td add "Fix bug" -p "Shared" --assign "Alice"
# Quick add with natural language
td quick "Call mom tomorrow at 5pm #Personal @important"
td quick "Submit report every Friday p1"
# Complete tasks
td done <task-id>
td done <id1> <id2> <id3> # Complete multiple
td done <id> --all-occurrences # Complete recurring task permanently
# Edit tasks
td edit <task-id> -c "New content"
td edit <task-id> -d "next week"
td edit <task-id> --add-label "urgent"
td edit <task-id> --no-due # Remove due date
td edit <task-id> --assign "Alice" # Assign to collaborator
td edit <task-id> --unassign # Remove assignment
# Delete tasks
td delete <task-id>
# Show task details
td show <task-id>
td show <task-id> --comments # Include comments
td show <task-id> --reminders # Include reminders
# Reopen completed tasks
td reopen <task-id>
Projects
td projects # List all projects
td projects add "New Project"
td projects add "Sub" --parent "Parent Project"
td projects show <id>
td projects edit <id> --name "Renamed"
td projects archive <id>
td projects unarchive <id>
td projects delete <id>
Sections
td sections # List all sections
td sections -p "Work" # Sections in Work project
td sections add "In Progress" -p "Work"
td sections edit <id> --name "Done"
td sections delete <id>
Labels
td labels # List all labels
td labels add "urgent"
td labels add "context/home" --color red
td labels edit <id> --name "important"
td labels delete <id>
Comments
td comments --task <task-id> # Comments on a task
td comments --project <project-id>
td comments add --task <id> "Comment text"
td comments edit <comment-id> "Updated text"
td comments delete <comment-id>
td comments attach --task <id> /path/to/file
td comments download <attachment-url>
Reminders
td reminders --task <task-id>
td reminders add --task <id> --due "2025-01-15T09:00:00"
td reminders add --task <id> --offset 30 # 30 min before due
td reminders delete <id>
Collaborators
td collaborators -p "Shared Project" # List collaborators
Saved Filters
td filters # List saved filters
td filters add "Work Today" --query "today & #Work"
td filters show <id>
td filters edit <id> --name "New Name"
td filters delete <id>
Configuration
td config show # Show current config
td config edit # Open in $EDITOR
td config set token "xxx" # Set API token
td config path # Print config file path
Token Storage Options
td supports three methods for storing your API token:
| Method | Security | Setup |
|---|---|---|
| OS Keyring | Most secure | Automatic on supported systems |
| Config file | Moderate | td config set token "xxx" |
| Environment | Varies | export TODOIST_TOKEN="xxx" |
The keyring uses:
- macOS: Keychain
- Windows: Credential Manager
- Linux: Secret Service API (requires libsecret/gnome-keyring)
Config File Location
| Platform | Path |
|---|---|
| macOS/Linux | ~/.config/td/config.toml |
| Windows | %APPDATA%\td\config.toml |
Shell Completions
# Generate completions
td completions bash > ~/.local/share/bash-completion/completions/td
td completions zsh > ~/.zfunc/_td
td completions fish > ~/.config/fish/completions/td.fish
Filter Expressions
Use the -f/--filter flag with td list to filter tasks using Todoist's filter syntax.
Date Filters
| Filter | Description |
|---|---|
today |
Tasks due today |
tomorrow |
Tasks due tomorrow |
overdue |
Tasks past their due date |
no date |
Tasks without a due date |
7 days |
Tasks due within the next 7 days |
Jan 15 |
Tasks due on January 15 |
December 25 |
Tasks due on December 25 |
Priority Filters
| Filter | Description |
|---|---|
p1 |
Priority 1 (highest, red) |
p2 |
Priority 2 (orange) |
p3 |
Priority 3 (yellow) |
p4 |
Priority 4 (default, blue) |
Label Filters
| Filter | Description |
|---|---|
@label |
Tasks with the specified label |
no labels |
Tasks without any labels |
Project and Section Filters
| Filter | Description |
|---|---|
#Project |
Tasks in exact project |
##Project |
Tasks in project and subprojects |
/Section |
Tasks in section |
Assignment Filters
| Filter | Description |
|---|---|
assigned to: me |
Tasks assigned to you |
assigned to: others |
Tasks assigned to someone else |
assigned to: Alice |
Tasks assigned to Alice |
assigned by: me |
Tasks you assigned |
assigned |
Tasks with any assignee |
!assigned |
Unassigned tasks |
Boolean Operators
| Operator | Description |
|---|---|
& |
AND - both conditions must match |
| |
OR - either condition matches |
! |
NOT - negates the condition |
() |
Grouping for precedence |
Examples
# High priority tasks due today or overdue
td list -f "p1 & (today | overdue)"
# Work tasks without a due date
td list -f "#Work & no date"
# Tasks with urgent label but not in Archive project
td list -f "@urgent & !#Archive"
# Tasks due this week in any Work subproject
td list -f "7 days & ##Work"
# Unlabeled tasks that are overdue
td list -f "no labels & overdue"
# Tasks due on a specific date
td list -f "Jan 15"
td list -f "December 25"
Output Formats
Human-readable (default for TTY)
Tasks display in a formatted table with colors for priorities and due dates.
JSON (default for non-TTY, or with --json)
td list --json
td list --json | jq '.[] | .content'
JSON output is automatically enabled when:
- Output is piped to another command
- Output is redirected to a file
- Running in a script
Use --json to force JSON output in interactive mode.
Quiet mode
td add "Task" -q # Only output the task ID
td done <id> -q # No output on success
Global Flags
These flags work with any command:
| Flag | Description |
|---|---|
--sync |
Sync with Todoist before executing |
--json |
Force JSON output |
--quiet, -q |
Quiet mode (errors only) |
--verbose, -v |
Show debug information |
--no-color |
Disable colored output |
--token <TOKEN> |
Override API token |
Environment Variables
| Variable | Description |
|---|---|
TODOIST_TOKEN |
API token (alternative to config file) |
NO_COLOR |
Disable colored output when set |
EDITOR |
Editor for td config edit |
Tips
Scripting with JSON
# Get all task IDs from a project
td list -p "Work" --json | jq -r '.[].id'
# Complete all overdue tasks
td list -f "overdue" --json | jq -r '.[].id' | xargs td done
# Export today's tasks
td today --json > today.json
Sync strategies
# Morning routine: sync once, then work offline
td sync
td today
td list -p "Work"
# Real-time workflow: sync with each command
alias tds="td --sync"
tds list
tds today
Shell aliases
# Add to your .bashrc or .zshrc
alias tdt="td today"
alias tdl="td list"
alias tda="td add"
alias tdd="td done"
alias tdq="td quick"
alias tds="td sync && td today"
Claude Code Integration
If you use Claude Code, there's a skill available that teaches Claude how to use the td CLI effectively. See skills/README.md for installation instructions.
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub.
License
MIT
Dependencies
~11–26MB
~316K SLoC