| Tool | What it does |
|---|---|
todo_list_items |
List todos/notes for a scope. Optional filters: kind (task/note/all), completed (open/done), textPrefix (prefix match), search (substring match anywhere in the text), tag (only items carrying that tag; pulls up a whole plan/group). Optional ordering: sortBy (creationDate/completionDate/completed) and order (asc/desc). Paginated (limit default 50, max 500; offset); a page is also capped by a character budget (maxChars), so it may return fewer than limit items with has_more set; item text is never truncated. |
todo_count_items |
Return todo/note counts per scope (no arguments): a cheap overview of where the open work is before paging a scope. Pass an optional tag to count only items carrying that tag; each scope then also reports a completed count, giving tag-scoped progress (e.g. "3 of 9 done"). |
todo_list_files |
List workspace files that have file-scoped todos, with per-file counts; paginated. |
todo_add_item |
Create a todo or note (isNote, isMarkdown optional). Optional position (top/bottom) overrides the createPosition setting for this call; omit it to use the setting. Write. |
todo_add_items |
Create several todos/notes in one call from an ordered items array, preserving the given order. Use it to lay down an ordered list (e.g. a multi-step plan) without the list coming out reversed. Each item may set its own isNote/isMarkdown; optional position (top/bottom, default bottom) places the whole block while keeping its order. Write. |
todo_update_text |
Change an item's text by id. Write. |
todo_set_completed |
Mark a todo completed/reopened by id. Write. |
todo_set_note |
Convert an item between task and note by id. Write. |
todo_set_markdown |
Toggle Markdown rendering for an item by id. Write. |
todo_set_tags |
Replace an item's tags by id with a given list (tags are normalized; an empty list clears them). Tag related items (e.g. every step of a plan), then read them back with the tag filter. Write. |
todo_delete_items |
Delete one or more items by their ids. Write. |
Resources: read-only JSON snapshots of the same data:
todo://user,todo://workspace: todos/notes for each scopetodo://counts: todo/note counts by scopetodo://files: files that have todostodo://file?path=<path>: todos for a specific file
Both tools and resources honor allowedScopes. There is also a vscodeTodo.mcp.transport setting, which currently only supports "streamableHttp".
User, Workspace & File-specific Management
Tasks and notes live in three scopes:
- User Tab: Data across all workspaces in the current profile (local by default; see Sync Modes (User and Workspace)).
- Workspace Tab: Data tied to the current workspace.
- File-specific Tab: Data for the active file. The tab follows the most recently focused file, but you can pin it or pick another file from the list.
File-specific lists match absolute paths; if a workspace-relative alias exists, they also match relative paths (useful for gist sync).
Sync Modes (User and Workspace)
User lists support Local, Profile Sync, and GitHub Gist. Workspace lists support Local or GitHub Gist; file lists live in the workspace gist file. Each mode stores data separately, so switching modes does not migrate existing todos.
User: Local Mode (Default)
Your user todos stay on the current VS Code profile and device only.
User: Profile Sync Mode
Syncs user lists with VS Code Settings Sync. Change the mode from the header Sync menu (User tab) or via VS Code Todo: Select User Sync Mode.
Warning: Profile Sync runs immediately on other machines using the same profile. Export first if you need separate copies.
GitHub Gist Sync Mode (User + Workspace)
Sync your todos via a GitHub Gist. This mode provides:
- Cross-profile sync across devices
- Multiple lists using different files within the gist (
user-Work.json,user-Personal.json, etc.) - Workspace + file lists stored in the same workspace file
- Independent sync from VS Code Settings Sync
Setup
- Connect GitHub: Open the Sync menu in the header and authenticate (requires
gistscope). - Choose your gist: Gist: Set ID... -> create secret gist, use existing, or open settings to paste an ID.
- Enable GitHub sync: In the User or Workspace tab, select GitHub Gist; optionally Change GitHub Gist list....
Note: GitHub sync is separate from Local/Profile modes. New gists start empty; use Export/Import to migrate data.
Command Palette commands:
- VS Code Todo: Connect GitHub
- VS Code Todo: Set Gist ID
- VS Code Todo: Select User Sync Mode / Select Workspace Sync Mode
- VS Code Todo: Change User List (GitHub Gist)... / Change Workspace List (GitHub Gist)...
- VS Code Todo: Sync Now
Gist file names use hyphen prefixes:
user-*.json- for user-scoped todos (e.g.,user-todos.json,user-Work.json)workspace-*.json- for workspace and file-scoped todos (e.g.,workspace-ProjectA.json)
Managing Your Gist
- View on GitHub: VS Code Todo: View Gist on GitHub
- Sync Manually: VS Code Todo: Sync Now or Sync all now in the Sync menu
- Create New Lists: Use the list selection commands or create
user-Name.json/workspace-Name.jsonon GitHub. - Rename Files: Rename on GitHub, then update settings to point to the new file names.
Sync Status Icons (GitHub sync): synced, pending changes, syncing, error.
Settings
Configure GitHub Gist sync with these settings:
{
// Gist ID (32-character hex string from gist URL). Never commit this.
"vscodeTodo.sync.github.gistId": "0123456789abcdef0123456789abcdef",
// User-scope file name in gist (uses hyphen prefix)
"vscodeTodo.sync.github.userFile": "user-todos.json",
// Workspace-scope file name in gist (auto-derived from workspace name if not set)
"vscodeTodo.sync.github.workspaceFile": "workspace-ProjectAlpha.json",
// Poll interval in seconds (min: 30, max: 600, default: 180)
"vscodeTodo.sync.github.pollInterval": 180,
// Only poll when Todo view is visible (saves battery & API rate limits)
"vscodeTodo.sync.pollOnlyWhenVisible": true
}
Note: User and workspace sync modes are set via the Sync menu or commands (not settings): Select User Sync Mode and Select Workspace Sync Mode.
Security Warnings
- Plaintext Storage: Todos synced to GitHub are stored in plaintext JSON. Never store passwords, API keys, tokens, or sensitive personal information.
- Gist ID Sensitivity: Your gist ID grants access to your todos. Never commit
.vscode/settings.jsoncontaining your gist ID. - Sharing: Use secret gists and remember that anyone with the gist ID can read and write your todos.
Conflict Resolution
The extension uses three-way, content-based conflict detection to protect your data.
Automatic Resolution: remote changed -> download; local changed -> upload after 3-second debounce; both unchanged -> no sync.
True Conflicts (both local and remote have changes):
- User lists: conflict wizard lets you resolve each conflict, keep all local, keep all remote, or view the gist on GitHub.
- Workspace lists: file path conflicts show Keep Local Files / Keep Remote Files / View Gist, then todo conflicts use the same wizard.
Best Practices:
- Syncs automatically when you open the view and polls periodically (default: every 3 minutes)
- Use Sync all now (Sync menu) or Sync Now (command) before major changes
Troubleshooting
"Not authenticated"
- Run VS Code Todo: Connect GitHub and sign in
"Gist ID not configured"
- Run VS Code Todo: Set Gist ID or set
vscodeTodo.sync.github.gistIdin Settings (User or Workspace)
"File not found in gist"
- The file will be auto-created on first sync, or create it manually on GitHub
Sync not happening
- Check status bar for error indicators
- Run VS Code Todo: Sync Now or click Sync all now in the Sync menu
- Verify the Todo view is visible (polling only happens when visible by default)
- Check
vscodeTodo.sync.pollOnlyWhenVisiblesetting if you need 24/7 background sync
Conflicts keep appearing
- The extension uses content-based detection to avoid false positives
- True conflicts only occur when both you and another user (or device) modify the same data
- Use the conflict wizard to resolve each conflict, or select Keep All Local / Keep All Remote / View Gist
Plans (Mobile PWA Companion)
Plans is an installable web app that opens the same lists on your phone, no VS Code required. It is the same UI as the webview with a touch layout, reading and writing the same GitHub Gist the extension syncs with.
- Nothing to install: open plans-app.pages.dev and "Add to Home Screen" for a standalone app.
- Same data: user and workspace lists sync through your gist, so edits on either side show up on the other.
- Works offline: the app shell is cached by a service worker and lists are kept in IndexedDB; changes sync when you are back online.
- Touch-friendly: larger targets, bigger text, and always-visible row actions on touch devices.
Setup
- Connect GitHub: tap Connect GitHub and enter the shown code at github.com/login/device. Uses the device flow with the
gistscope only; the token stays on your device. - Pick a gist: paste a gist ID, or browse your gists to pick or create a secret one. Use the same gist as the extension. See GitHub Gist Sync Mode.
- Choose lists: select the
user-*.jsonandworkspace-*.jsonfiles to sync.
The same plaintext-storage and gist-ID cautions apply. See Security Warnings. The MCP server is VS Code-only and is not available in the PWA.
Markdown Support for Todos and Notes
Create todos and notes with rich markdown formatting. You can switch rendering between text and markdown per item from the options menu.

Syntax Highlighting
When rendering in markdown, you can include code snippets with syntax highlighting. This is supported by ngx-markdown and PrismJS, which supports hundreds of languages.
For example, to highlight TypeScript code:
```typescript
const myProp: string = 'value';
console.log(myProp);
```
Supported Syntax Highlighting Languages (click to expand)
| Markup & SGML | Programming Languages | Scripting & Markup | Data Format & DB | Systems & Config | Miscellaneous |
|---|---|---|---|---|---|
| HTML, XML | C, C++, C# | JavaScript, TypeScript | JSON, JSON5 | Bash, Shell | Markdown, YAML |
| SVG, MathML | Java, Kotlin | Python, Ruby | SQL, GraphQL | Apache Configuration | Docker, Dockerfile |
| SSML, Atom, RSS | Go, Rust | PHP, ASP.NET | CSV, TOML | nginx, Systemd | Git, Regex |
| Ada, Agda | Swift, Scala | Perl, Lua | Protocol Buffers | HTTP, HPKP | LaTeX, Tex, Context |
| ABAP, ActionScript | Haskell, Clojure | R, MATLAB | GraphQL | .ignore (gitignore) | WebAssembly, WebGL |
| ANTLR4, G4 | Objective-C, Dart | Elixir, Erlang | EditorConfig | ASN.1, CSP | |
| Apex, APL | F#, Ocaml | PowerShell | INI, DNS Zone File | VHDL, Verilog | |
| AppleScript, AQL | Groovy, Ruby | Shell Session | Robot Framework | Mermaid, PlantUML | |
| Arduino, ARM Assembly | Fortran, COBOL | AutoHotkey, AutoIt | Puppet, Bicep | GameMaker Language | |
| Arturo, AsciiDoc | Haskell, TypeScript | Lua, MoonScript | AWS, Google Cloud Config | Gherkin, GraphQL | |
| ASP.NET (C#) | Julia, Rust | Tcl, Terraform | Ansible, Terraform | Diff, Patch | |
| Assembly (Various) | Nim, Crystal | Scheme, Lisp | Kubernetes, Docker | UML, DOT (Graphviz) | |
| AWK, GAWK | Perl, PHP | Swift, VB.Net | Prometheus, Grafana | XMPP, IRC | |
| Bison, BNF, RBNF | Prolog, Python | TypeScript | Nagios, Zabbix | LaTeX, SAS, R |
Note: This table represents a subset of the languages supported by PrismJS. For a full list, please refer to the PrismJS supported languages page.
Mermaid Diagram Support
You can create diagrams and charts using Mermaid syntax. To render a Mermaid diagram, switch the item to markdown and wrap your Mermaid code in a mermaid block:
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
Toggle Diagram Rendering
To show Mermaid code instead of rendered diagrams, set:
"vscodeTodo.enableMarkdownDiagrams": false
KaTeX Math Support
Render mathematical expressions using KaTeX in Markdown items. Enable "View as Markdown" for the item, then use KaTeX delimiters. Math is not rendered inside fenced code blocks (```).
Inline math:
$a^2 + b^2 = c^2$Block math (put on separate lines, no backticks):
$$ \int_0^\infty e^{-x^2},dx = \frac{\sqrt{\pi}}{2} $$
Supported delimiters include $...$, $$...$$, \( ... \), and \[ ... \].
Toggle Math Rendering
To show math delimiters as plain text, set:
"vscodeTodo.enableMarkdownKatex": false
Customizable Sorting
Sorting options:
- sortType1: Moves completed todos to the bottom, just on top of the first completed todo.
- sortType2: Similar to Type 1, but groups completed todos with notes, useful for maintaining contextual relationships.
- disabled: Completed todos remain in place, allowing full manual control of the order.
Default: sortType1.
"vscodeTodo.taskSortingOptions": "sortType1"
Tags
Tag any todo or note to group related items. For example, label every step of a plan with the same tag, then pull the whole group up at once and track its progress.
- Add or remove tags: open an item for editing; a tag input appears next to the dates in the edit footer. Type a tag and press Enter (or click away) to add it. You can also enter a comma-separated list and it's split into several tags. Click the × on a chip, or press Backspace in an empty input, to remove one. Tags are normalized automatically (trimmed, de-duplicated case-insensitively, with a sensible length/count cap).
- Show Tags: tag chips are hidden by default to keep dense lists clean. Turn them on from the gear/settings menu (Show Tags / Hide Tags), or set
vscodeTodo.showTagsdirectly. Chips then appear under each item in both the collapsed and expanded views. - Filter by tag: click a chip to filter the list to that tag, or type
tag:<name>in the search box. A plain search query also matches tags (not just the item text); atag:query matches only tags, so it pulls up exactly the items in that plan/group.
Tags are part of the item, so they sync and round-trip through JSON export/import like any other field. AI agents can read and set them through the MCP server (the tag filter on todo_list_items / todo_count_items and the todo_set_tags tool; see MCP Server (AI Agent Integration)), so a plan laid down by an agent and one tagged by hand share the same grouping.
"vscodeTodo.showTags": true
Auto delete completed todos after a specified number of days
Set vscodeTodo.autoDeleteCompletedAfterDays to the number of days, or 0 to disable.
"vscodeTodo.autoDeleteCompletedAfterDays": 7
Collapsed item preview lines
Set vscodeTodo.collapsedPreviewLines to the number of lines (minimum 1, default 1).
"vscodeTodo.collapsedPreviewLines": 2
Webview Font Settings
Webview typography settings:
vscodeTodo.webviewFontFamily: CSS font-family string. Leave empty to inherit VS Code's font.vscodeTodo.webviewFontSize: Number in pixels. Set0to inherit VS Code's editor font size.
Example:
"vscodeTodo.webviewFontFamily": "'Fira Code', Consolas, 'Courier New', monospace",
"vscodeTodo.webviewFontSize": 18
Status Bar Integration
Status bar shows task and note counts.

Import from JSON / Markdown
Command Palette: Import data from JSON or Import data from Markdown.
Import file must be in the workspace root. JSON import is lossless (preserves metadata and filesDataPaths); Markdown import is lossy (text and checkbox state only).
JSON details:
- If an
idmatches an existing record, the provided values override the existing ones. Otherwise, a new record is added. textis the only required property (and thefile pathfor file-specific records). OptionalfilesDataPathspreserves file list path aliases.
JSON example (click to expand)
{
"user": [
{ /* if the id matches an existing record, the provided values will override the existing ones. */
"id": 1234567890123456,
"text": "Complete the project documentation",
"completed": false,
"isMarkdown": true,
"isNote": false,
"creationDate": "2024-05-19T12:34:56.789Z"
},
{
/* if the id is not provided or does not match an existing record, a new record is added. */
"text": "Review pull requests",
}
],
"workspace": [
{
"id": 3456789012345678,
"text": "Set up new workspace",
"completed": false,
"isMarkdown": false,
"isNote": true,
"creationDate": "2024-05-20T10:00:00.789Z"
}
],
"files": {
"c:\\Users\\username\\Documents\\project\\README.md": [
{
"id": 4567890123456789,
"text": "Add installation instructions",
"completed": false,
"isMarkdown": true,
"isNote": false,
"creationDate": "2024-05-18T14:22:33.456Z"
}
],
"c:\\Users\\username\\Documents\\project\\src\\main.js": [
{
"id": 5678901234567890,
"text": "Refactor main function",
"completed": true,
"isMarkdown": false,
"isNote": false,
"creationDate": "2024-05-17T16:00:00.789Z",
"completionDate": "2024-05-17T18:30:00.123Z"
}
]
},
"filesDataPaths": {
"c:\\Users\\username\\Documents\\project\\README.md": {
"absPaths": ["c:\\Users\\username\\Documents\\project\\README.md"],
"relPaths": ["README.md"]
},
"c:\\Users\\username\\Documents\\project\\src\\main.js": {
"absPaths": ["c:\\Users\\username\\Documents\\project\\src\\main.js"],
"relPaths": ["src/main.js"]
}
}
}
Export to JSON / Markdown
Command Palette: Export to JSON (lossless) or Export to Markdown (lossy).
The exported file is saved in the workspace root folder. JSON export includes filesDataPaths; Markdown export is presentation-ready but lossy.
Contributing
Contributions are welcome! Please submit pull requests, report bugs, or suggest enhancements via the GitHub repository.
License
Distributed under the MIT License. See LICENSE for more information.
Support
For support, feature requests, or bug reporting, please visit the GitHub issues page.
Important Notice
Data Safety: This extension is provided "as-is" under the MIT License. Keep backups via Export. GitHub Gist sync depends on GitHub availability and uses content-based conflict detection for simultaneous edits.
Security: Never store passwords, API keys, tokens, or other sensitive information in your todos. Data synced to GitHub Gists is stored in plaintext JSON format.
Legal: DISCLAIMER | LICENSE
