Toudou

A workspace-scoped todo list living right in your VS Code sidebar. Organize tasks with categories, priorities, drag & drop, and full undo/redo — no cloud, no account, everything stays local.

Features
Todos
- Add, complete, delete and restore todos from the sidebar or the Command Palette
- Priorities — high, medium, low — shown as inline labels and sortable
- Descriptions — optional details visible in tooltips
- Checkbox integration — check to complete, uncheck to restore
- Double-click a todo to rename it instantly
Categories
- Create, rename, and delete categories — add and delete buttons sit inline on each row
- Assign an emoji to each category
- Move todos between categories via the context menu or drag & drop
Drag & Drop
- Reorder todos within a category
- Move todos between categories or to/from uncategorized
- Reorder categories themselves
Sorting
Four sort modes available from the title bar:
| Mode |
Description |
| Manual |
Your own ordering via drag & drop |
| Priority |
Flat list, highest priority first |
| Category |
Grouped by category, manual order inside |
| Category + Priority |
Grouped by category, sorted by priority inside |
History (Toudones)
Completed todos are moved to the Toudones panel where you can restore them individually or purge them all.
Undo / Redo
Every action is undoable (up to 50 states). Keyboard shortcuts:
- Undo:
Ctrl+Z / Cmd+Z (when panel is focused)
- Redo:
Ctrl+Shift+Z / Cmd+Shift+Z
Export / Import
- Export your todos (or a selection) to a JSON file
- Import from a JSON file — categories are auto-created as needed
- File size capped at 5 MB for safety
Filter
Search todos by title or description in both panels.
In Progress
Mark a todo as "in progress" — it gets a green icon to show what you're actively working on.
Copilot Integration
Right-click a todo and select Open in Copilot to start a chat session with the task context pre-filled. The todo gets a green "in progress" icon while you work on it.
Six Language Model Tools are also registered so Copilot can create, list, complete, delete todos and manage categories on your behalf.
Storage
- Data is stored per workspace, by default in VS Code's
workspaceStorage — outside your repo unless you ask for it
- Each project can be pointed at its own file, in the workspace or anywhere on disk
- The file can be shared with another editor, window or machine without either side losing edits
- Inspect the raw JSON anytime with Toudou: Open Storage File
Localization
Fully translated in English and French. VS Code picks the right language automatically.
Commands
All commands are available under the Toudou category in the Command Palette (Ctrl+Shift+P):
| Command |
Description |
| Add Todo |
Create a new todo (with optional category and description) |
| Complete Todo |
Mark a todo as done |
| Delete Todo |
Permanently remove a todo |
| Create Category |
Add a new category |
| Rename Category |
Rename an existing category |
| Delete Category |
Remove a category (todos become uncategorized) |
| Restore from Toudones |
Bring back a completed todo |
| Purge Toudones |
Delete all completed todos |
| Change Priority |
Set priority on a todo |
| Filter Todos |
Search in the todo list |
| Export Todos |
Export todos to a JSON file |
| Import Todos |
Import todos from a JSON file |
| Open Storage File |
View the raw JSON data |
| Set Workspace Storage Path |
Change where this workspace stores its todos |
| Reload Storage File |
Re-read the storage file from disk immediately |
| Reset Storage Location |
Forget this workspace's storage choice and ask again |
Settings
| Setting |
Description |
toudou.defaultStoragePath |
Default path to the storage file. Accepts {workspace} and ~. |
toudou.defaultAddMode |
Which flow the + button runs: quick (title only) or complete. Default: quick. |
toudou.watchExternalChanges |
Reload the storage file when another app edits it. Default: true. |
toudou.watchIntervalSeconds |
How often the file is checked for external changes: 2, 3, 5 or 10. Default: 3. |
toudou.defaultStoragePath is machine-scoped: it can only be set in your user or remote settings, never by a workspace, since it decides where the extension writes. In a remote window (WSL, SSH, Codespaces) the Settings editor lists it under the Remote tab rather than User — the machine it applies to is the remote one, and a path means something different on each side.
The three other settings are application-scoped: they live in your user settings only, shared by every window, and no workspace can change them.
toudou.defaultStoragePath sets the default for every workspace on this machine. It accepts:
- Relative path — resolved from the workspace root (e.g.
.vscode/toudou.json). Must stay inside the workspace.
- Absolute path — any location on disk (a warning is shown once per path).
~ — expanded to your home directory.
{workspace} placeholder — replaced with a sanitized version of the workspace folder name (e.g. ~/.toudou/{workspace}.json).
Where a project stores its todos
Until a project has been given a storage location, the empty Toudou view asks where its todos should live:
| Choice |
Result |
| Create in workspace |
.vscode/toudou.json, next to the project and committable if you want it to be |
| Choose a file or folder… |
pick a file to use it as-is, or a folder to create toudou-{workspace}.json in it |
| Keep the default location |
keeps the invisible default in workspaceStorage |
The question lives in the view rather than in a notification: it waits instead of disappearing after a few seconds, and it costs nothing to ignore. Picking an existing file never overwrites it — Toudou reads it and merges its own writes into it, keeping anything it does not recognize.
The same choices stay available at any time under Toudou: Set Workspace Storage Path (also in the view's … menu), which shows where the workspace currently writes and adds two more: enter a path by hand — the only form that accepts {workspace} and ~ — or reset to the machine default. Toudou: Reset Storage Location does that reset directly, with a confirmation naming the file it stops using.
Whichever way it is set, the per-workspace choice takes precedence over toudou.defaultStoragePath and is stored outside the project, so cloning a repository never changes where your todos are written. Nothing on disk is touched when it changes — only the pointer to it.
Sharing the storage file
The storage file can be shared with the Obsidian Toudou plugin, another VS Code window, or another machine through a synced folder (Synology Drive, OneDrive…) — the on-disk format is identical.
Every change is applied on top of a fresh read of the file and saved through a temporary file renamed into place, so a write never rests on a stale copy and a reader never sees a half-written file. Anything Toudou does not recognize — keys or entries written by another client — is preserved as-is instead of being dropped on the next save. External changes appear in the tree within a few seconds without reloading the window; Toudou: Reload Storage File forces an immediate re-read.
Two windows on the same machine are serialized by that read-modify-write, so neither loses the other's edit. Across machines the last writer still wins: the sync client, not Toudou, decides which revision lands, and a simultaneous edit on both ends may produce a conflict copy.
Development
Open in VS Code with Dev Containers to get the full dockerized dev environment.
Scripts
| Script |
Description |
npm run compile |
Build the extension |
npm run watch |
Build in watch mode |
npm run typecheck |
Run TypeScript type checking |
npm run lint |
Run ESLint |
npm run format |
Format with Prettier |
npm test |
Run the storage unit tests |
npm run check |
Run typecheck + lint + format check + tests |
npm run package |
Package as .vsix (runs check + minified build first) |
Tests
npm test runs the suite on Node's built-in test runner — no framework, no extra dependency.
Two levels:
test/storageCore.test.ts covers the pure helpers directly: round-tripping a file another client also writes, comparing revisions, normalizing manual order.
test/storageService.test.ts covers the service itself against test/helpers/vscodeStub.ts, an in-memory vscode module that esbuild substitutes for the real one (--alias:vscode=…). The service is exercised unmodified, so the tests cover the code that ships rather than a copy of its logic. The stub's failure hook makes any filesystem operation fail on demand, which is how the corrupt, missing and locked-file paths are reached.
Debug
Press F5 to launch an Extension Development Host with the extension loaded.
Contributing
Contributions are welcome! Whether it's a bug fix, a feature suggestion, or a documentation improvement — feel free to open an issue or submit a pull request.
License
MIT