todoist-sync
Dev task tracker synced to Todoist. Auto-triggered via hooks on SessionStart and Stop in configured projects. Fetches due tasks, completes sub-tasks after work, creates chunks from plans. Use /todoist-sync:setup to configure a project.
todoist-sync
Keeps Todoist in sync with Claude Code sessions. Uses mcp__todoist__* MCP tools.
Step 0: Load config
Before doing anything, read the config file. The path ${CLAUDE_PLUGIN_DATA} is substituted by Claude Code:
cat "${CLAUDE_PLUGIN_DATA}/config.json"
If the file doesn't exist, tell the user to run /todoist-sync:setup and stop.
Parse the JSON to find the current repo's project entry. Match git rev-parse --show-toplevel against the repo field in each project. Extract section_id, section_name, and preferences.summary_max_tasks.
On Session Start
The SessionStart hook injects context with the pre-resolved section ID, max tasks, branch, and session file path. All discovery is already done — do NOT call get-overview, search, find-projects, or find-sections.
Exactly one MCP call:
mcp__todoist__find-tasks({ sectionId: "<from hook context>", limit: <from hook context> })
Then from the results:
- Filter to overdue + due this week
- Show brief summary (5-10 lines max):
- Overdue tasks (flag these)
- Due today / this week
- Total open chunks vs sub-tasks
- If a task description mentions a branch, note if it matches current branch
Never search for the project or section by name. The hook already resolved it.
During Session
Completing sub-tasks
When a piece of work is done (code written, tests pass, PR merged):
- Identify which Todoist sub-tasks were addressed
- Complete them via
mcp__todoist__complete-tasks - Update session state — add completed task IDs to
active_task_idsin the session file provided by the hook context. Use atomic write to prevent corruption:
Replacepython3 -c " import json, sys, os, tempfile path = sys.argv[1] new_ids = sys.argv[2:] with open(path) as f: state = json.load(f) state['active_task_ids'] = list(set(state.get('active_task_ids', []) + new_ids)) fd, tmp = tempfile.mkstemp(dir=os.path.dirname(path), suffix='.tmp') with os.fdopen(fd, 'w') as f: json.dump(state, f, indent=2) f.flush() os.fsync(f.fileno()) os.replace(tmp, path) " "SESSION_FILE_FROM_HOOK_CONTEXT" "TASK_ID_1" "TASK_ID_2"SESSION_FILE_FROM_HOOK_CONTEXTwith the actual path from the SessionStart hook context. - If all sub-tasks of a parent chunk are done, ask if the chunk should be completed too
Updating task descriptions
When significant progress is made, append session context to the parent chunk's description via mcp__todoist__update-tasks:
---
**Session: YYYY-MM-DD**
Branch: `branch-name`
Done: what was accomplished
Next: what remains
Append, don't replace existing description content.
On Session Stop
The Stop hook injects context with: project key, section name, branch, active task IDs, session file path.
When you receive this context:
- If
active_task_idsis empty, skip — nothing was tracked this session - If tasks were tracked, briefly note what was completed
- Offer to update any parent chunk descriptions with session context
- Do NOT do a full section scan — only act on the active task IDs
Creating Tasks from Plans
When a plan is written (plan mode exit) in a configured project:
- Offer to create matching Todoist tasks (don't auto-create without asking)
- Each major plan step becomes a chunk (parent task) in the project's section
- Each sub-step becomes a sub-task under the chunk
- Apply labels based on content:
quick-win: <30 min, targeted fix, single-file changeblocked: depends on external API, waiting on someone, infra not readyneeds-design: UI work, architecture decision, multiple valid approaches
- Set priority:
p1: blocking other workp2: due this week or next deliverablep3: planned but not urgentp4: backlog / nice-to-have
- Search before creating — use
mcp__todoist__find-taskswithsearchTextto avoid duplicates
Task Naming Rules
- Chunks: verb + deliverable — "Build FastAPI backend", "Fix coverage page bug", "Merge Phase 2 branches"
- Sub-tasks: specific action — "Add test for endpoint", "Wire service to x_api.py", "Run full test suite"
- Never vague: no "Work on X", "Look into Y", "Investigate Z" — always specific and completable
What Claude Manages vs User Manages
| Claude manages | User manages (phone/Todoist app) |
|---|---|
| Creating chunks + sub-tasks from plans | Due dates and deadlines |
| Completing sub-tasks after work | Reordering priorities |
| Applying labels based on context | Moving tasks between sections |
| Updating descriptions with session state | Recurring task schedules |
| Suggesting new tasks from TODOs/FIXMEs | Deleting tasks they don't want |
Rules
- Never create duplicate tasks. Search first via
mcp__todoist__find-tasks. - Never set due dates unless the user explicitly asks or the plan has a deadline.
- Never delete tasks. Only complete them or update them.
- Keep it lightweight. Only sync at session boundaries and plan exits.
- Descriptions are breadcrumbs. Branch names, state, context — so the user can pick up later.
- Sub-tasks are karma generators. 3-6 per chunk. Each should feel like progress when checked off.