Skip to content

MakotoUwu/ticktick-cli

Repository files navigation

ticktick-cli

Agent-native command-line interface for TickTick
Full API coverage · JSON-first · Built for AI agents and humans alike

Unofficial Python 3.10+ PyPI MIT License API Coverage CI Tests Output Modes


I was frustrated that no proper TickTick CLI existed. The official API covers only tasks and projects, third-party SDKs are incomplete, MCP servers add unnecessary context overhead, and none of these approaches are designed for the way modern AI agents actually work. So I built ticktick-cli -- a CLI that covers 100% of TickTick's API surface (including the unofficial V2 endpoints), outputs structured JSON by default, and works equally well when invoked by a human or by Claude Code via Bash.

Why CLI, not MCP or SDK?

The emerging consensus from practitioners like Peter Steinberger and Armin Ronacher is clear: CLI-first, MCP only when necessary. AI coding agents (Claude Code, Codex, Cursor) already invoke tools via shell -- that's their native interface. Adding an MCP server is an extra process, an extra protocol, and extra context pollution that doesn't add value when a CLI already outputs structured JSON. Benchmarks show CLI achieves higher task completion at equivalent token cost. The Unix philosophy was accidentally designed for AI agents decades before they existed.


Highlights

  • JSON output by default -- structured {"ok": true, "data": [...]} responses, parseable by any agent or script
  • --human flag -- switch to rich terminal tables with a single flag
  • 100% API coverage -- tasks, subtasks, projects, folders, tags, kanban columns, habits, focus/pomodoro (including live timer), filters, templates, user profile
  • Dual API support -- V1 (official OAuth 2.0) + V2 (unofficial session-based) for full feature access
  • Focus timer control -- start, stop, log, and delete pomodoro sessions directly from CLI
  • Multiple output formats -- JSON (default), CSV, YAML, or rich terminal tables (--human)
  • Natural language dates -- --due tomorrow, --start "next monday", --due "in 3 days"
  • Agent-friendly design -- no interactive prompts, --yes flags, --dry-run, deterministic exit codes (0/1/2)
  • Field selection -- --fields id,title,priority to return only what you need
  • Multiple profiles -- --profile work / --profile personal for separate accounts
  • Security-first -- OAuth CSRF protection, encrypted credential storage (600 permissions), env var support for secrets
  • Shell completions -- bash, zsh, fish auto-complete out of the box
  • Retry with backoff -- automatic retries for transient API errors, V1 token auto-refresh

Table of Contents

Installation

From source (development)

git clone https://github.com/MakotoUwu/ticktick-cli.git
cd ticktick-cli
python -m venv .venv && source .venv/bin/activate
pip install -e .

pip

pip install ticktick-agent-cli

pipx (isolated install)

pipx install ticktick-agent-cli

The published package name is ticktick-agent-cli; the installed command remains ticktick.

Claude Code plugin

This repository now includes a marketplace-ready Claude Code plugin bundle under claude-plugin/ticktick-cli.

For local development and testing:

claude plugin validate .
claude plugin validate ./claude-plugin/ticktick-cli

From a Claude Code session started in the repository root:

/plugin marketplace add .
/plugin install ticktick-cli@ticktick-cli-marketplace

The plugin provides a reusable TickTick operator Skill plus packaged Claude commands for agenda review and task capture.

Quick Start

1. Authenticate

# V2 session (recommended -- unlocks all features)
ticktick auth login-v2 --username you@email.com
# Password is prompted securely (or set TICKTICK_PASSWORD env var)

# V1 OAuth (official API -- tasks & projects only)
export TICKTICK_CLIENT_ID="your_client_id"
export TICKTICK_CLIENT_SECRET="your_client_secret"
ticktick auth login --client-id "$TICKTICK_CLIENT_ID" --client-secret "$TICKTICK_CLIENT_SECRET"

2. Start using it

# List your tasks (JSON)
ticktick task list

# Same thing, but as a rich table
ticktick --human task list

# Add a task (natural language dates!)
ticktick task add "Review pull request" --priority high --due tomorrow

# Complete it
ticktick task done TASK_ID

# What's overdue?
ticktick task overdue

# Check your habits
ticktick --human habit list

# Start a 25-minute focus session
ticktick focus start --duration 25

# Inspect linked calendar accounts
ticktick calendar account list

# Inspect upcoming linked calendar events
ticktick calendar event list --limit 10

# Distinguish TickTick-owned entries from external mirrors
ticktick --fields title,sourceType,linkedTaskId,calendarName calendar event list --limit 10

# Resolve a TickTick-owned calendar entry to its backing task
ticktick calendar event task EVENT_ID

# Check focus timer status
ticktick focus status

# Focus stats for the last 30 days
ticktick focus heatmap --days 30

# Output as CSV or YAML
ticktick task list --output csv
ticktick habit list --output yaml

# Select specific fields
ticktick task list --fields id,title,priority

# Full account sync
ticktick sync

JSON output (default)

{
  "ok": true,
  "data": [
    {
      "id": "abc123",
      "title": "Review pull request",
      "priority": "high",
      "status": "active",
      "dueDate": "2026-03-11T00:00:00.000+0000"
    }
  ],
  "count": 1
}

Rich table output (--human)

                             Tasks
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ id       ┃ title                  ┃ priority ┃ dueDate      ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ abc123   │ Review pull request    │ high     │ 2026-03-11   │
│ def456   │ Buy groceries          │ none     │ 2026-03-12   │
└──────────┴────────────────────────┴──────────┴──────────────┘

Commands

Domain Commands API
Tasks add list show edit done abandon delete move search today overdue completed trash pin unpin batch-add duplicate convert activity comment list comment add comment delete V1+V2
Subtasks set unset list V2
Projects list create show edit delete V1+V2
Folders list create rename delete V2
Tags list create edit rename merge delete V2
Kanban column list create edit delete V2
Habits list show create edit delete checkin history archive unarchive V2
Focus start stop status log delete stats heatmap by-tag V2
Filters list show create edit delete V2
Templates list show create delete V2
User profile status stats preferences V2
Config set get list path --
Auth login login-v2 logout status refresh --
Utilities sync schema completion version V2

Global Options

Flag Description
--human Rich table output instead of JSON
--output FORMAT Output format: json (default), csv, yaml
--fields FIELDS Comma-separated list of fields to include
--dry-run Preview what would happen without making changes
--verbose Enable debug output
--profile NAME Auth profile to use (default: default)
--version Show version
--help Show help for any command

Output Format

Every command returns a consistent JSON envelope:

Success:  {"ok": true, "data": <result>, "count": <n>}
Message:  {"ok": true, "message": "Task created."}
Error:    {"ok": false, "error": "description"}

Exit Codes

Code Meaning
0 Success
1 General error (API error, invalid input)
2 Authentication error (not logged in, expired token)

Agent Integration

ticktick-cli follows the agent-native CLI design pattern -- the same approach used by gh, git, and docker with Claude Code, Codex, and Cursor. An AGENTS.md file is included for agent discovery (compatible with the AGENTS.md standard adopted by 60,000+ repositories).

No ANSI escape codes in JSON mode -- output is always clean, parseable JSON.

No interactive prompts -- use --yes to skip confirmations for destructive actions:

ticktick task delete TASK_ID --yes
ticktick project delete PROJECT_ID --yes

Deterministic exit codes -- agents can check $? to determine success/failure without parsing output.

Pipe-friendly -- combine with jq for complex queries:

# Get titles of all high-priority tasks
ticktick task list --priority high | jq -r '.data[].title'

# Count overdue tasks
ticktick task overdue | jq '.count'

# Get habit names and streaks
ticktick habit list | jq '.data[] | {name, currentStreak}'

Environment variables for auth -- no secrets in command args:

export TICKTICK_USERNAME="you@email.com"
export TICKTICK_PASSWORD="secret"
export TICKTICK_CLIENT_ID="your_id"
export TICKTICK_CLIENT_SECRET="your_secret"

Why not MCP? MCP servers add a separate process, a custom protocol, and consume thousands of tokens just from tool descriptions being loaded. A CLI that outputs JSON is already a perfect tool interface -- Claude Code calls it via Bash, parses the JSON, and moves on. Zero overhead, universal compatibility, and it works with any agent that has shell access.

Authentication

V1: Official OAuth 2.0

The official API supports tasks and projects. Requires a developer app:

  1. Go to developer.ticktick.com and create an app
  2. Set redirect URI to http://localhost:8080/callback
  3. Run:
ticktick auth login --client-id YOUR_ID --client-secret YOUR_SECRET

This opens your browser for OAuth authorization and stores the token locally.

V2: Session-based (recommended)

The unofficial V2 API unlocks everything: habits, tags, focus stats, kanban, folders, subtasks, and more.

ticktick auth login-v2 --username you@email.com
# Password is prompted securely

Note: V2 uses the same API the TickTick web app uses. It sends your password over HTTPS to TickTick's servers. If you're uncomfortable with this, use V1 OAuth for the subset of features it supports.

Multiple profiles

ticktick --profile work auth login-v2 --username work@company.com
ticktick --profile personal auth login-v2 --username me@gmail.com

ticktick --profile work task list
ticktick --profile personal habit list

Check auth status

ticktick auth status

Configuration

Config files live at ~/.config/ticktick-cli/<profile>/ (XDG-compliant).

# See where config is stored
ticktick config path

# List all settings
ticktick config list

# Set a value
ticktick config set default_project "Work"

# Get a value
ticktick config get default_project

Security

  • Credentials stored with 600 permissions -- only your user can read auth.json
  • Atomic file writes -- no TOCTOU race condition where credentials are briefly world-readable
  • OAuth CSRF protection -- state parameter validated on callback
  • No secrets in process args -- password is prompted interactively or read from env vars
  • Error messages sanitized -- API responses truncated to prevent token/credential leakage
  • Profile name validation -- prevents directory traversal attacks

Contributing

# Clone and set up
git clone https://github.com/MakotoUwu/ticktick-cli.git
cd ticktick-cli
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Run tests
pytest -v

# Build release artifacts
uv build

# All 439 tests should pass

Releasing

  1. Update version in pyproject.toml.
  2. Move the relevant notes from CHANGELOG.md into a dated release section.
  3. Run local release checks:
ruff check src/ tests/
pytest -v --tb=short
uv build
uvx twine check dist/*
  1. Push main.
  2. For a staging publish, run the Publish Python Package GitHub Actions workflow with the testpypi target.
  3. For a production publish, create and publish a GitHub Release (or manually dispatch the workflow with the pypi target).

The repository includes a trusted-publishing-ready workflow in .github/workflows/publish.yml. One-time setup is still required in GitHub environments and in the PyPI/TestPyPI Trusted Publisher settings.

Project Structure

src/ticktick_cli/
  api/
    base.py        # Shared HTTP transport with retry & backoff
    v1.py          # Official OAuth2 API client
    v2.py          # Unofficial session API client (incl. focus timer)
    client.py      # Unified TickTickClient
  models/
    task.py        # Task, TaskPriority, TaskStatus
    project.py     # Project, ProjectKind, ProjectViewMode
    tag.py         # Tag
    habit.py       # Habit, HabitCheckin
    pomodoro.py    # Pomodoro, FocusOperation, PomodoroStatus
    comment.py     # Comment, Activity, UserProfile
    filter.py      # Filter, FilterRule, FilterCondition
    template.py    # TaskTemplate
  commands/
    auth_cmd.py    # login, login-v2, logout, status, refresh
    task_cmd.py    # 22 task commands + comments + convert
    project_cmd.py # CRUD for projects
    folder_cmd.py  # CRUD for folders
    tag_cmd.py     # tag management + merge
    kanban_cmd.py  # kanban columns
    subtask_cmd.py # subtask parent/child
    habit_cmd.py   # habit tracking + checkins
    focus_cmd.py   # pomodoro timer + stats
    filter_cmd.py  # saved filters (smart lists) CRUD
    template_cmd.py # task templates CRUD
    user_cmd.py    # profile, stats, preferences
    config_cmd.py  # CLI config management
    schema_cmd.py  # CLI structure discovery for agents
  auth.py          # OAuth2 + V2 auth flows
  config.py        # XDG config management
  output.py        # JSON/CSV/YAML/Rich table output
  dates.py         # Natural language date parsing
  exceptions.py    # Custom exception hierarchy
  cli.py           # Main entry point

Why This Over the Official CLI?

This is an unofficial, community-built CLI. TickTick released their own @ticktick/ticktick-cli in March 2025, and various MCP servers exist on the LobeHub registry. Here's how they compare:

Feature ticktick-cli (this) Official CLI MCP Servers
Commands 70+ ~12 5-15
API coverage V1 + V2 (100%) V1 only V1 only
Habits, Focus, Kanban Yes No No
Filters, Templates Yes No No
Comments, Activity feed Yes No No
JSON-first output {"ok": true, "data": ...} --json flag JSON-RPC
CSV / YAML / Rich tables Yes No No
--dry-run All mutating commands No No
--fields selection Yes No No
schema introspection Yes No Partial
Natural language dates Yes No No
Retry with backoff Yes No No
Shell completions bash, zsh, fish No N/A
Works without runtime Yes (just Python) Yes (Node.js) Needs MCP host
Agent-native design Built for it Afterthought Agent-only
Human-friendly --human tables Basic No

TL;DR: The official CLI covers basic task/project CRUD. MCP servers are agent-only with limited coverage. This CLI covers the entire API surface, works for both humans and agents, and includes features like focus timers, habits, and kanban that no other tool provides.

Roadmap

Done

  • Shell completions (bash, zsh, fish)
  • V1 token auto-refresh
  • CI/CD with GitHub Actions
  • CSV and YAML output formats
  • Natural language date parsing
  • Field selection (--fields)
  • Dry-run mode (--dry-run)
  • Retry with exponential backoff
  • Focus/Pomodoro live timer control
  • Pydantic models for all entities
  • schema command for agent discovery
  • Task comments (list, add, delete)
  • Activity feed / change history
  • Task duplicate
  • Smart lists / saved filters
  • Task templates (save/reuse)
  • Task ↔ Note conversion
  • Read-only calendar discovery commands (calendar account list, calendar subscription list, calendar event list)
  • Publish package to PyPI
  • Configure Trusted Publishing for repeatable PyPI/TestPyPI releases
  • Package a local Claude Code plugin + marketplace bundle

Next

  • Submit a Claude Code plugin directory entry
  • Publish native skill distribution for OpenClaw / ClawHub
  • Homebrew formula
  • Advanced productivity reports
  • Focus session ↔ task linking

Disclaimer

This project is an unofficial CLI for TickTick and is not affiliated with, endorsed by, or associated with TickTick or Appest Inc. in any way. Use at your own risk.

License

MIT

About

Agent-native CLI for TickTick — full API coverage, JSON-first, built for AI agents and humans alike

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors