TickTick
A skill for working with TickTick via ticktick-cli (npm package ticktick-cli, binaries
ticktick and tt) — a TypeScript wrapper around the official TickTick Open API
(https://developer.ticktick.com/docs#/openapi).
A Russian translation of this document is available in SKILL.ru.md.
Install & auth (one-time setup)
npm install -g ticktick-cli
- Go to https://developer.ticktick.com/ → "Manage Apps" → create an app.
Set the redirect URI to exactly:
http://127.0.0.1:18463/callback(the CLI's default). - Save the Client ID/Secret into the CLI config:
ticktick config set clientId YOUR_CLIENT_ID ticktick config set clientSecret YOUR_CLIENT_SECRET - Authenticate:
This opens a browser; after you approve, the token is stored locally (ticktick auth login~/Library/Application Support/ticktick-cli/config.jsonon macOS) and auto-refreshes. - Verify:
ticktick auth status.
Critical: proxy workaround for sandboxes without direct network access
If the agent is running in a sandbox where outbound traffic only goes through an HTTP(S) proxy
(HTTP_PROXY/HTTPS_PROXY), note that Node.js does not honor those variables by default in
fetch. Because of this, a plain ticktick <command> may fail with fetch failed /
ENOTFOUND api.ticktick.com, even though curl to the same host works fine.
Fix — run commands with the NODE_USE_ENV_PROXY=1 environment variable:
NODE_USE_ENV_PROXY=1 ticktick <command> [...]
In a normal terminal (not a sandbox) this variable is harmless — it's safe to always add it "just in case".
Command surface (important: NOT tasks/projects plural)
The main subcommands are ticktick auth, ticktick task, ticktick project, plus the shortcuts
ticktick today / ticktick overdue / ticktick next. This version of the CLI has no setup
wizard beyond the manual steps above, no tags flag on task creation, no short IDs, and no separate
MCP server — it's a plain CLI invoked through the shell.
Daily overview commands (fastest way to answer "what's on my plate today")
NODE_USE_ENV_PROXY=1 ticktick today --json # overdue + due today
NODE_USE_ENV_PROXY=1 ticktick overdue --json # only overdue open tasks
NODE_USE_ENV_PROXY=1 ticktick next --json # the next 10 upcoming tasks after today
Projects (lists)
NODE_USE_ENV_PROXY=1 ticktick project list
NODE_USE_ENV_PROXY=1 ticktick project get <projectId>
NODE_USE_ENV_PROXY=1 ticktick project data <projectId> # project + tasks + columns
NODE_USE_ENV_PROXY=1 ticktick project create --name "Name" --color "#F18181" --view-mode list --kind TASK
NODE_USE_ENV_PROXY=1 ticktick project update <projectId> --name "New name"
NODE_USE_ENV_PROXY=1 ticktick project delete <projectId>
Note: the built-in Inbox project is not returned by project list — this is a limitation of the
TickTick Open API itself, not the CLI. You can find the Inbox projectId on any task that lives in
it (e.g. via ticktick next --json or ticktick today --json); it usually looks like
inbox<number>.
Tasks
# Create a task
NODE_USE_ENV_PROXY=1 ticktick task create --project-id <id> --title "Title" \
--content "Extra text" --due-date "2026-01-30T09:00:00+0000" --priority 3
# Get a task
NODE_USE_ENV_PROXY=1 ticktick task get <projectId> <taskId>
# Update a task
NODE_USE_ENV_PROXY=1 ticktick task update <taskId> --project-id <id> --title "New title" --priority 5
# Complete / delete
NODE_USE_ENV_PROXY=1 ticktick task complete <projectId> <taskId>
NODE_USE_ENV_PROXY=1 ticktick task delete <projectId> <taskId>
# Move a task between projects
NODE_USE_ENV_PROXY=1 ticktick task move --from-project-id <id1> --to-project-id <id2> --task-id <taskId>
# List completed tasks
NODE_USE_ENV_PROXY=1 ticktick task completed --project-id <id>
# Filter (by date/priority/tag/status)
NODE_USE_ENV_PROXY=1 ticktick task filter --project-id <id> --priority 3 --tag work --status 0
--priority values are TickTick API numbers (0 = none, 1 = low, 3 = medium, 5 = high) — the CLI
does not accept the words high/medium/low, even though older docs for this project might
suggest otherwise.
Date format: yyyy-MM-dd'T'HH:mm:ssZ, e.g. 2026-01-30T09:00:00+0000.
--all-day true gotcha: for all-day tasks, TickTick stores dueDate/startDate as
21:00:00 UTC of the previous local day (i.e. midnight in Europe/Moscow, UTC+3). To make a task
land in today/overdue for calendar date YYYY-MM-DD, you must set the date to
(YYYY-MM-DD minus 1 day)T21:00:00+0000, not the date itself with T21:00:00+0000. Setting it
"as-is" pushes the task one day forward and it won't show up in ticktick today until tomorrow.
Verify the result with ticktick today --json after creating/updating an all-day task.
Careful with --json: on today/overdue/next it's a boolean output-format switch ("print
JSON"). On task create/task update/task filter/task move/project create/project update
it's an inline request body that requires a valid JSON string after the flag
(--json '{"title":"..."}'). If you just append --json with no value to task create, the CLI
fails with error: option '--json <json>' argument missing.
Raw API request
If there's no dedicated flag for what you need, you can hit any documented endpoint directly:
NODE_USE_ENV_PROXY=1 ticktick request GET /open/v1/project
NODE_USE_ENV_PROXY=1 ticktick request POST /open/v1/task --json '{"title":"...","projectId":"..."}'
Practical workflow
- If the user names a project instead of giving an ID, run
project listfirst and resolve theidfromname. - For "what's on my plate today" use
ticktick today --json— don't hand-assemble it viafilter. - Always add
--json(or the equivalent output flag on subcommands that support it) when working from a script/agent, so you can parse the output instead of the table. - Secrets (
clientSecret,accessToken) live in the config file in plaintext — don't print its contents to the user unless necessary, and don't logauth statusoutput without an explicit--show-secretsrequest.