dms-todoman-plugin
August 28, 2026 · View on GitHub
A DankMaterialShell (DMS)
DankBar widget for your CalDAV to-dos, backed by
todoman. It puts your open-task count in
the bar and opens a popout where you can browse tasks grouped by due date,
complete them, and add or edit tasks inline — all driven by the todo CLI, so
your .ics files stay the single source of truth.
AI disclaimer: The QML frontend was built with the help of AI, following DankMaterialShell's Material Design scheme so it matches the rest of the shell.
Important
todoman is required. This plugin is a front-end for the todo command; it
does not read or write .ics files on its own (except a tiny Python helper for
renaming/clearing fields). Without a working todo on PATH the widget shows
an error. See Requirements.
Requirements
| Requirement | Why | Notes |
|---|---|---|
todoman (todo on PATH) | Every action shells out to todo | Needs a working ~/.config/todoman/config.py pointing at your .ics task dirs |
| DankMaterialShell ≥ 1.5 | Host shell / plugin API | Declared as requires_dms in plugin.json |
python3 on PATH | ics_edit.py renames a task and clears due/priority | Only invoked when you edit those fields |
todoman itself reads CalDAV VTODOs from local .ics directories — typically
kept in sync with a CalDAV server via
vdirsyncer. Setting that up is out of scope
here; if todo list works in your terminal, this plugin will work.
Features
-
Bar pill with a checklist icon and a live open-task count. Optionally (setting Show next task in the bar) it also carries the next due task and a countdown — the soonest task still ahead, falling back to the most recently missed one when nothing is upcoming. The title is truncated so the pill cannot push the rest of the bar around; a vertical bar shows the countdown only.
-
Due-date grouping in the popout — tasks are split into fixed sections, and empty sections are hidden:
Group Contains Overdue Due before today Due today Due today Due tomorrow Due tomorrow Upcoming Due in 2+ days No due date Undated tasks -
One-click complete —
todo done <id>, with an optimistic checked state. -
Inline create — summary plus optional list, due date/time, and priority (
todo new). -
Inline edit — change summary, list (
todo move), due date, and priority; clearing due/priority is handled by the bundledics_edit.py. -
Delete with an inline confirm step (
todo delete --yes). -
Each row shows a priority dot, the due date, and the list name — the list name is hidden while the view is already narrowed to one list.
-
Per-list view — an
All lists/ per-list dropdown in the popout header filters what you see instantly. It filters client-side, so switching lists spawns no process, cannot fail on a stale list name, and leaves the bar's task count global. It is view state, not a setting: it resets with the shell. -
Configurable watched lists, sort field, refresh interval, and a show-completed toggle (see Settings).
How it works
- The widget runs
todo --porcelain listand renders the JSON. Task ids are todoman's own — the same onestodo list/todo doneprint — so completing or editing a task uses ids that stay valid. The list is refetched after every create/complete/edit so ids never go stale. - List names come from
todo lists, which only exists in todoman ≥ 4.7. On older versions that call fails silently, so the names are recovered from the tasks themselves; the only thing lost is a list that currently holds no tasks. Filtering by list happens inside the widget, never by refetching withtodo list <name>— that would make the bar's count follow the filter and would hard-fail on a list that vanished between two refreshes. - All mutations go through the
todoCLI, except renaming a summary and clearing a due date or priority, which the CLI can't do directly; those go throughics_edit.py, a small pass over the task's.icsfile.
Settings
| Key | Meaning | Default |
|---|---|---|
listFilter | Comma-separated list names the widget watches (empty = all) | "" |
defaultList | Default list for new tasks (empty = todoman default) | "" |
sortField | Order within each group: due | priority | created_at | summary | due |
showCompleted | Include done/cancelled tasks | false |
showNearestTask | Append the next due task + countdown to the bar pill | false |
refreshInterval | Reload interval, in minutes | 5 |
Grouping by due date is always on; sortField controls the order of tasks
within each group.
listFilter and the header dropdown are different scopes and never overlap:
listFilter decides which lists the widget fetches at all — it is passed
straight to todo list — while the dropdown narrows the view within them.
A list that is dropped from listFilter, deleted, or renamed resets the view
to All lists rather than leaving you staring at an empty popout.
Installation
Nix flake (declarative)
Add the repo as a flake input and hand it to the DMS plugins option — the
attribute name becomes the plugin directory under
~/.config/DankMaterialShell/plugins/, and it must match the id in
plugin.json (dankTodoman):
# flake.nix
inputs.dms-todoman-plugin = {
url = "github:Shochraos/dms-todoman-plugin";
flake = false;
};
# home-manager module (where you configure DMS)
programs.dank-material-shell.plugins.dankTodoman = {
enable = true;
src = inputs.dms-todoman-plugin;
# settings = { sortField = "priority"; showCompleted = false; };
};
Manual / local path
Point a home.file / xdg.configFile entry (or just copy the folder) at your
DMS plugins directory:
xdg.configFile."DankMaterialShell/plugins/dankTodoman".source = ./.;
Either way, restart DMS (or its systemd user service) after installing so it picks the plugin up.
Files
| File | Purpose |
|---|---|
plugin.json | Plugin manifest (id, capabilities, requirements) |
TodomanWidget.qml | The bar pill + popout UI and all todo interaction |
TodomanSettings.qml | Settings page shown in DMS |
ics_edit.py | Rename summary / clear due / clear priority in an .ics |
License
MIT © 2026 Shochraos