Agentic CLI for Todoist using the official Todoist API v1 (REST). It supports task, project, section, label, and comment management, plus an agent plan/apply workflow that can be wired to an external planner.
- Fast capture and triage without leaving the terminal.
- Scriptable output (
--json/--plain/--ndjson) for automation and integrations. - Agent workflows for bulk plans with safe previews and confirmations.
See docs/SPEC.md for the CLI contract and docs/ROADMAP.md for planned features.
- Batch changes with human review via plan/apply.
- Safer automation with
--dry-run,--confirm, and--on-error. - Easy scheduling without running a daemon.
brew install agisilaos/tap/todoist-cli
todoist --version
todoist auth login # prompts for token (or use --token-stdin)
todoist add "Review PR 42"
todoist task list # lists Inbox tasks in a tablego build ./cmd/todoist
./todoist --helpHomebrew (recommended):
brew tap agisilaos/tap
brew install todoist-cliUse a personal API token from Todoist settings.
todoist auth loginOther options:
todoist auth login --token-stdin < token.txt
TODOIST_TOKEN=... todoist task listTokens are stored in ~/.config/todoist/credentials.json with 0600 permissions. Set TODOIST_TOKEN to override stored tokens.
User config (non-secrets):
~/.config/todoist/config.json
Project config (non-secrets only):
./.todoist.json
Example config.json:
{
"base_url": "https://api.todoist.com/api/v1",
"timeout_seconds": 10,
"default_profile": "default",
"default_inbox_labels": ["inbox"],
"default_inbox_due": "today",
"table_width": 120
}Precedence (high → low):
- Flags
- Environment variables
- Project config (
.todoist.json) - User config (
~/.config/todoist/config.json)
Environment variables:
TODOIST_TOKENTODOIST_PROFILETODOIST_CONFIGTODOIST_TIMEOUTTODOIST_BASE_URLTODOIST_OAUTH_CLIENT_ID(OAuth client ID used byauth login --oauth)TODOIST_OAUTH_AUTHORIZE_URL(override OAuth authorize URL)TODOIST_OAUTH_TOKEN_URL(override OAuth token URL)TODOIST_OAUTH_DEVICE_URL(override OAuth device-code URL)TODOIST_OAUTH_LISTEN(override OAuth callback listen address)TODOIST_FUZZY(1 to enable fuzzy name resolution)TODOIST_ACCESSIBLE(1 to add screen-reader-friendly labels in human output)TODOIST_TABLE_WIDTH(override table width for human output)
todoist [global flags] <command> [args]
Global flags apply to every command:
-h, --help Show help
--version Show version
-q, --quiet Suppress non-essential output
--quiet-json Compact single-line JSON errors (for scripts/agents)
-v, --verbose Enable verbose output
--accessible Add text markers for screen-reader-friendly task output
--json JSON output
--plain Plain text output
--ndjson NDJSON output
--no-color Disable color
--no-input Disable prompts
--timeout <seconds> Request timeout (default 10)
--config <path> Config file path
--profile <name> Profile name (default "default")
-n, --dry-run Preview changes without applying
-f, --force Skip confirmation prompts
--fuzzy Enable fuzzy name resolution
--no-fuzzy Disable fuzzy name resolution
--progress-jsonl Emit progress events as JSONL to stderr or file
--base-url <url> Override API base URL
Flag parsing notes:
- Global flags can appear before or after commands/subcommands.
- Subcommand flags can be mixed with positional refs/content (for example
todoist add "Buy milk" --project Home --dry-run). - Common aliases:
ls=list,rm/del=delete(task,project,section,label,comment), andshow=view(task). - Prefer
--jsonor--ndjsonfor scripts/agents.
Manage Todoist credentials and profiles.
todoist auth login [--token-stdin] [--print-env]
todoist auth login --oauth [--client-id <id>] [--no-browser] [--print-env]
todoist auth login --oauth-device [--client-id <id>] [--print-env]
[--oauth-authorize-url <url>] [--oauth-token-url <url>]
[--oauth-device-url <url>] [--oauth-listen <host:port>] [--oauth-redirect-uri <uri>]
todoist auth status
todoist auth logout
auth loginprompts for a token (TTY) or reads from stdin with--token-stdin. Stores tokens in~/.config/todoist/credentials.json(0600).auth login --oauthruns OAuth PKCE via local callback (http://127.0.0.1:8765/callbackby default). If browser auto-open fails, the command prints a warning and continues waiting for callback so you can open the URL manually.auth login --oauth-deviceruns OAuth Device Flow (good for headless/CI/SSH); it prints verification URL/code and polls until authorized.auth statusprints active profile and whether a token is present.auth logoutdeletes stored credentials for the active profile.- Use
--print-envto emitTODOIST_TOKEN=...for piping into other tools (--json/--ndjsonreturn structured output with the export string).
List and modify tasks (IDs or names accepted where noted).
todoist task list [--filter <query>] [--preset today|overdue|next7] [--project <id|name>] [--section <id|name>] [--label <name>] [--completed] [--completed-by completion|due] [--since <date>] [--until <date>] [--sort due|priority] [--truncate-width <cols>] [--wide] [--all-projects]
todoist task add --content <text> [flags]
todoist task view <ref> [--full]
todoist task update <ref> [flags]
todoist task move <ref> [--project <id|name>] [--section <id|name>] [--parent <id>]
todoist task move --filter <query> [--project <id|name>] [--section <id|name>] [--parent <id>] --yes
todoist task complete <ref>
todoist task complete --filter <query> --yes
todoist task reopen <ref>
todoist task delete <ref> [--yes]
Task flags:
By default, todoist task list shows your Inbox tasks. Use --all-projects or a filter to list across projects.
--content <text> Task content ("-" reads stdin)
--description <text> Task description
--project <id|name> Project reference
--section <id|name> Section reference
--parent <id> Parent task ID
--label <name> Label name (repeatable)
--priority <1-4> Priority (accepts p1..p4)
--due <string> Natural language due
--due-date <YYYY-MM-DD> Due date
--due-datetime <RFC3339> Due date/time
--due-lang <code> Due language
--duration <minutes> Duration in minutes
--duration-unit <unit> Duration unit (minute/day)
--deadline <YYYY-MM-DD> Deadline date
--assignee <ref> Assignee reference (id, me, name, email)
--natural Parse quick-add style tokens in content (#project @label p1..p4 due:...)
--yes Skip delete confirmation
Completed task listing:
todoist task list --completed [--completed-by completion|due] [--since <date>] [--until <date>]
Notes:
--since/--untilacceptYYYY-MM-DD, RFC3339,today,yesterday, weekday names (for examplemonday), and relative forms like2 weeks ago.- If you pass
--sincewithout--until,--untildefaults to today. - Bulk commands using
--filteraccept Todoist query syntax; plain text is treated as search text. --strictis a flag ontodoist add(quick-add command), not ontodoist task add.task add/update --naturallets you pass quick-add style tokens in--content(for example#Home @errands p2 due:tomorrow) and maps them to REST fields.- Task references also support due hints for disambiguation:
"call mom today","call mom tomorrow","call mom overdue".
Table options:
--wide Wider columns for table output
--all-projects List tasks from all projects (default is Inbox)
--preset today|overdue|next7 Shortcut filters (ignored if --filter set)
--sort due|priority Client-side sort for active tasks
--truncate-width <cols> Override table width (human output)
Examples:
todoist task list --filter "@work & today"(human table)todoist task list --preset today --sort prioritytodoist task list --completed --since "2 weeks ago" --jsonecho "Write launch blog #Marketing @writing p2 due:friday" | todoist add --content -todoist task move --id 123 --project "Personal" --section "Errands"todoist task view id:123456 --fulltodoist task complete "Pay rent"
todoist workspace list
todoist project collaborators <id|name>
workspace listshows workspaces available to the authenticated user.project collaboratorslists collaborators for a shared project.
todoist filter list
todoist filter show <id|name>
todoist filter add --name <name> --query <query> [--color <color>] [--favorite]
todoist filter update <id|name> [--name <name>] [--query <query>] [--color <color>] [--favorite|--unfavorite]
todoist filter delete <id|name> --yes
Quick add to Inbox with optional defaults.
todoist inbox add --content <text> [--label <name> ...] [--due <string>|--due-date <date>|--due-datetime <datetime>] [--priority <1-4>] [--description <text>] [--section <id|name>]
Notes:
- Reads content from stdin with
--content -. - Applies defaults from config:
default_inbox_labels,default_inbox_due. todoist add <text>uses Todoist quick add parsing for#Project,@label,p1..p4, and natural language dates.- In quick-add mode,
--sectionand project IDs are rejected; use--strictto fall back to REST add. - In
--strictmode, use REST-style flags (--project Home,--label errands,--due tomorrow) without#,@, ordue:prefixes.
Examples:
echo "Capture idea" | todoist inbox add --content -todoist inbox add --content "Pay rent" --label finance --due "1st"todoist add "Pay rent #Home p2 due:tomorrow"todoist inbox(list inbox tasks)
Quick list of tasks due today and overdue.
todoist today
Shortcut for listing completed tasks.
todoist completed [--completed-by completion|due] [--since <date>] [--until <date>] [--project <id|name>] [--section <id|name>] [--filter <query>]
List tasks due in the next N days (default 7).
todoist upcoming [days] [--project <id|name>] [--label <name>] [--sort due|priority] [--wide]
Create and manage projects.
todoist project list [--archived]
todoist project view <id|name>
todoist project browse <id|name>
todoist project add --name <name> [--description <text>] [--parent <id|name>]
todoist project create --name <name> [--description <text>] [--parent <id|name>]
todoist project update --id <project_id> [flags]
todoist project move <id|name> (--to-workspace <id|name> | --to-personal) [--visibility restricted|team|public] [--yes]
todoist project archive --id <project_id>
todoist project unarchive --id <project_id>
todoist project delete --id <project_id>
Examples:
todoist project list --archived --jsontodoist project view "Home"todoist project browse "Home"todoist project add --name "Side Projects" --description "Weekend hacks"todoist project create --name "Side Projects" --description "Weekend hacks"todoist project update --id 234 --name "Side Projects (2024)"todoist project move "Team Project" --to-personal --yestodoist project move "Home" --to-workspace "Acme Corp" --visibility team --yes
Create and manage sections within projects.
todoist section list [--project <id|name>]
todoist section add --name <name> --project <id|name>
todoist section update --id <section_id> --name <name>
todoist section delete --id <section_id>
Example: todoist section add --name "Backlog" --project "Side Projects"
Create and manage labels.
todoist label list
todoist label add --name <name> [--color <color>] [--favorite]
todoist label update --id <label_id> [--name <name>] [--color <color>] [--favorite | --unfavorite]
todoist label delete --id <label_id>
Example: todoist label add --name focus --color red --favorite
Create and manage comments for tasks or projects.
todoist comment list --task <id> | --project <id>
todoist comment add --content <text> (--task <id> | --project <id>)
todoist comment update --id <comment_id> --content <text>
todoist comment delete --id <comment_id>
Examples:
todoist comment list --task 123 --jsontodoist comment add --task 123 --content "Need QA sign-off"
Manage task reminders (Todoist Sync API).
todoist reminder list [task] [--task <ref>]
todoist reminder add [task] [--task <ref>] (--before <duration> | --at <datetime>)
todoist reminder update [id] [--id <id>] (--before <duration> | --at <datetime>)
todoist reminder delete [id] [--id <id>] [--yes]
Manage live notifications (Sync API).
todoist notification list [--type <types>] [--unread|--read] [--limit <n>] [--offset <n>]
todoist notification view [id] [--id <id>]
todoist notification accept [id] [--id <id>]
todoist notification reject [id] [--id <id>]
todoist notification read [id] [--id <id>] [--all --yes]
todoist notification unread [id] [--id <id>]
accept/reject work for share_invitation_sent notifications.
View account/project activity logs.
todoist activity [--since <date>] [--until <date>] [--type task|comment|project] [--event <type>] [--project <id|name>] [--by <id|me>] [--limit <n>] [--cursor <cursor>] [--all]
View productivity stats and completion progress.
todoist stats
todoist stats goals [--daily <n>] [--weekly <n>]
todoist stats vacation (--on | --off)
Manage account settings and notification preferences.
todoist settings
todoist settings view
todoist settings update [flags]
todoist settings themes
settings view prints human-friendly labels (for example 24h, DD-MM-YYYY, theme names) and resolves start_page references like project?id=<id> to names when possible.
Open Todoist web URLs with equivalent CLI commands.
todoist view <url>
Examples:
todoist view https://app.todoist.com/app/task/call-mom-6f3qg8mgqp99mFVJtodoist view https://app.todoist.com/app/project/home-2203306141todoist view https://app.todoist.com/app/settings
For project URLs with deprecated legacy IDs, view attempts a slug/name fallback before using the URL ID directly.
Integrate with an external planner to generate and apply bulk plans.
todoist agent plan <instruction> [--out <file>] [--planner <cmd>]
todoist agent apply <instruction> --confirm <token> [--planner <cmd>] [--policy <file>]
todoist agent apply --plan <file> --confirm <token>
todoist agent apply --plan <file> --confirm <token> --dry-run [--policy <file>]
todoist agent apply --plan <file> --confirm <token> --on-error fail|continue
todoist agent run --instruction <text> [--planner <cmd>] [--confirm <token>|--force] [--policy <file>]
todoist agent schedule print --weekly "sat 09:00" [--instruction <text>] [--planner <cmd>] [--confirm <token>|--force] [--cron]
todoist agent examples
todoist agent planner
todoist agent planner --set --cmd "<planner>"
todoist agent planner --json
todoist planner --json
todoist agent status
agent plansends context + instruction to an external planner command. Use--outto save the plan JSON.agent applyexecutes a plan from--planor re-runs the planner; requires the--confirmtoken from the plan.agent statusis safe on first run; it reports planner configuration and whether a last plan exists.--dry-runwithagent applyprints the plan without applying actions.- In
--dry-run, no-action plans are allowed (useful for CI/pipeline contract checks). --on-error=continuekeeps applying actions after a failure and reports statuses.- Human apply/run output includes a summary block (ok/failed/skipped replay), destructive-action count, per-action-type counts, and final outcome.
--plan-versionenforces expected plan.version (default 1). Unknown versions are rejected.agent plannershows/sets the planner command (uses config/planner_cmd or TODOIST_PLANNER_CMD).agent runcombines plan + apply for automation (cron/launchd).agent schedule printemits a scheduler entry (launchd by default; use--cron).- Context flags:
--context-project,--context-label,--context-completed 7dlimit planner context. - Planner context now includes active tasks (capped) in addition to projects/sections/labels/completed tasks.
--policy <file>enforces action-policy rules (allow_action_types,deny_action_types,max_destructive_actions).--progress-jsonl[=path]emits JSONL progress events foragent run/apply(stderr by default). Key lifecycle events includeagent_plan_loaded,agent_action_validated,agent_action_dispatched,agent_action_succeeded/agent_action_failed, andagent_apply_summary.- Agent apply/run keeps a replay journal (
agent_replay.json) and skips already-applied actions from the same plan token.
Planner contract checklist:
- Emit valid JSON to stdout matching
todoist schema --name plan. - Include
confirm_tokenandactionswith supported types. - Optional: include
reasonper action for richer human review output. - Use stable action fields (IDs or names as documented).
Scheduling example (macOS launchd):
todoist agent schedule print --weekly "sat 09:00" --instruction "Move 3 articles from Learning to Today" > ~/Library/LaunchAgents/com.todoist.agent.weekly.plist
launchctl load ~/Library/LaunchAgents/com.todoist.agent.weekly.plistCron example:
todoist agent schedule print --weekly "sat 09:00" --instruction "Move 3 articles from Learning to Today" --cronContext scoping example:
todoist agent run --instruction "Pick 3 articles for today" --context-project "Learning" --context-label article --context-completed 7dRun environment and auth checks:
todoist doctor
todoist doctor --strictdoctor validates config/credentials health, token presence, API reachability, planner setup, policy parsing, and replay journal readability.
Output JSON schemas (use --json):
todoist schema [--name task_list|task_item_ndjson|error|plan|plan_preview|planner_request] [--json]
Generate a completion script for your shell:
todoist completion bash > /usr/local/etc/bash_completion.d/todoist
todoist completion zsh > "${fpath[1]}/_todoist"
todoist completion fish > ~/.config/fish/completions/todoist.fish
# Or install to a sensible default location:
todoist completion install bash
# Auto-detect your shell from $SHELL:
todoist completion install
# Remove installed scripts:
todoist completion uninstall
todoist completion uninstall zshcompletion install prints an activation hint (source ...); for zsh ensure the directory is in $fpath and run autoload -U compinit && compinit.
Some operations require IDs (e.g., task update/complete/delete; project archive/delete). Use list commands in --plain or --json mode to locate IDs:
todoist task list --filter "content:\"Write launch blog\"" --plain
todoist project list --plain
todoist comment list --task <task_id> --plain
todoist task list --completed --since "yesterday" --json | jq -r '.[].id'Where supported, name resolution is built-in (e.g., --project <name> and --section <name> on task commands, --label <name>), but task IDs are required for update/complete/delete. Use id:<id> to explicitly reference IDs.
Task/project/label/filter references also accept Todoist app URLs, for example:
todoist task view https://app.todoist.com/app/task/call-mom-abc123
todoist project rm --id https://app.todoist.com/app/project/home-2203306141 --dry-run
todoist filter show https://app.todoist.com/app/filter/today-f1- Destructive commands (delete/archive) prompt when stdin is a TTY;
todoist task deleterequires--yes(no prompt). Use--forceto skip prompts. In non-interactive mode (--no-input), destructive commands fail unless--forceis set. --dry-runpreviews the actions that would be sent to Todoist without performing them.--no-inputdisables all prompts (auth included). Provide required flags or env vars to continue.
- TTY defaults to a human-readable table with truncated columns for readability and resolves project/section IDs to names when possible.
- Non-TTY defaults to
--plain(tab-separated, no headers). --jsonoutputs raw JSON arrays/objects (no envelope).--ndjsonoutputs one JSON object per line (streaming friendly) across task/project/section/label/comment lists.- Errors go to stderr;
--quietsuppresses non-error informational messages.--verbosemay show request IDs and more detail. - Color is enabled by default on TTY; use
--no-colororNO_COLOR=1to disable. --accessible(orTODOIST_ACCESSIBLE=1) adds explicit text markers for task due/priority values in human output.--truncate-widthorTODOIST_TABLE_WIDTHlets you set table width;--wideexpands columns.- Fuzzy name resolution can be enabled with
--fuzzyorTODOIST_FUZZY=1(project/section/label names);--no-fuzzydisables.
Plain output columns:
task list:id, content, project_id, section_id, labels, due, priority, completedproject list:id, name, parent_id, is_archived, is_sharedsection list:id, name, project_id, is_archivedlabel list:id, name, color, is_favoritecomment list:id, content, posted_at
0success1generic failure2invalid usage3auth error4not found5conflict- Errors return human-readable messages;
--jsonerrors include{"error": "...", "meta": {"request_id": "..."}}.
todoist agent plan delegates planning to an external command defined by TODOIST_PLANNER_CMD or --planner. The command must read JSON from stdin and output a plan JSON document to stdout.
Planner input schema:
{
"instruction": "Move overdue tasks to Catch Up",
"profile": "default",
"now": "2025-02-08T12:34:56Z",
"context": {
"projects": [ ... ],
"sections": [ ... ],
"labels": [ ... ]
}
}Plan output schema:
{
"version": 1,
"instruction": "Move overdue tasks to Catch Up",
"created_at": "2025-02-08T12:34:56Z",
"confirm_token": "6f2b",
"summary": { "tasks": 12, "projects": 0, "sections": 0, "labels": 1, "comments": 0 },
"actions": [
{ "type": "task_move", "task_id": "123", "project_id": "2203306141" },
{ "type": "task_update", "task_id": "123", "labels": ["overdue"] }
]
}Supported action types:
task_add,task_update,task_move,task_complete,task_reopen,task_deleteproject_add,project_update,project_archive,project_unarchive,project_deletesection_add,section_update,section_deletelabel_add,label_update,label_deletecomment_add,comment_update,comment_delete
Action field notes:
- Task/section/comment actions accept explicit IDs (
project_id,section_id) or reference fields (project,section) where applicable. comment_addmust includecontentand one target:task_idorproject/project_id.
make release-check VERSION=vX.Y.Z
make release-dry-run VERSION=vX.Y.Z
make release VERSION=vX.Y.ZRelease scripts:
scripts/docs-check.shvalidates release-related docs coverage in README.scripts/release-check.shvalidates version/tag preconditions, runs tests/vet/docs/format checks, and verifies stamped version output.scripts/release.shrunsrelease-check, updates changelog from git history, builds darwin archives, publishes GitHub release/tag, and updates the Homebrew tap formula.
- CLI specification:
docs/SPEC.md - Roadmap:
docs/ROADMAP.md - Release runbook:
RELEASING.md - Release history:
CHANGELOG.md
- POST body size limit: 1 MiB
- Header size limit: 65 KiB
- Processing timeout: 15 seconds for standard requests
- This CLI uses Todoist REST API v1 endpoints under
https://api.todoist.com/api/v1. - Keychain integration is not implemented; tokens are stored in a local credentials file.
- Some Todoist surfaces (for example skill/update) are not implemented yet.
- Todoist is a trademark of Doist; this project is an independent, unofficial CLI.
- Shell completions are bundled via
todoist completion.
# List Inbox tasks with defaults
todoist task list
# List completed tasks finished this week in JSON
todoist task list --completed --since "monday" --json
# Add a task from stdin content
echo "Write release notes" | todoist task add --content -
# Move a task to a project/section by name
todoist task move --id 123456 --project "Side Projects" --section "Backlog"
# Add a label and favorite it
todoist label add --name focus --favorite
# Add a comment to a task
todoist comment add --task 123456 --content "Need QA sign-off"
# Generate a plan with an external planner and apply it
todoist agent plan "Clean up overdue tasks" --out plan.json
todoist agent apply --plan plan.json --confirm "$(jq -r .confirm_token plan.json)"