The missing task layer for Roam
Turn native TODOs into scheduled and recurring tasks with inline pills, a powerful dashboard, and optional Today widget/badge β all stored as plain Roam blocks.
β Roam-native storage (child blocks) β’ β Recurring + one-off scheduled tasks β’ β Subtasks & dependencies β’ β Actively maintained
Support / bugs: Please message me in the Roam Slack (include repro steps + any console output if relevant):
https://app.slack.com/client/TNEAEL9QW/
If you use TODOs in Roam, Better Tasks gives you:
in any block and it becomes a live task list β real Roam blocks with working checkboxes, clickable refs and inline pills, plus a result count and refresh button (filters: `status`, `project`, `due`, `completed`, `blocked`, `assignee`, `query`, `limit`, `sort`). Project, waiting-for and context values are now written as `[[page links]]`, so native blocks and Datalog find your tasks with no extension involvement β and each value gets a real page with linked references. Inline pills also render on every copy of a task now, including native query results, ``s and linked references, not just the first one on the page. Full guide with copy-paste Datalog snippets: docs/query-cookbook.md. Existing tasks are untouched; re-save an attribute to upgrade it, or turn page links off in settings.Shift+I. Dismissals persist with a 30-day cooldown. Pure local heuristics β no AI, no API calls. Master switch plus per-rule toggles in settings. Also available programmatically via bt_get_suggestions.on the 1st and 15th of each month (and any multi-day rule including the 1st) skipped the 1st whenever the schedule crossed a month boundary β it now lands on every listed day. every month on the second tuesday and every 3 months on the 2nd tuesday were both being treated as a plain weekly Tuesday, ignoring the monthly interval. every other tuesday scheduled weekly rather than fortnightly. And first monday of september failed to parse unless you appended every year. If you use any of these patterns, check the next due date on the affected tasks β open the β― menu β View series to see the corrected upcoming occurrences. The recurrence engine now ships with an automated test suite to prevent regressions..ics files are now valid iCalendar. Task titles and project names containing a comma, semicolon or backslash β Buy milk, eggs is enough to trigger it β were written unescaped and could be truncated or mis-parsed on import; they are now escaped per RFC 5545. Each event also gains the required DTSTAMP property, and long titles use standard line folding, so strict importers accept the file. CSV export now also quotes values containing a carriage return. If you previously imported a Better Tasks calendar and titles looked mangled, re-export.BT_attrNotes:: child block, configurable label). An append-only activity log records every change β snoozes, completions, reopens, attribute edits, recurrence spawns β as children of an Activity log container block under the task. Events are timestamped, tagged by source (dashboard / inline / API / bulk), and carry structured data for future Smart Suggestions. View the history from the dashboard β― menu β View activity (slide-in panel, reverse-chronological). Settings: master enable toggle (on by default), opt-in title-edit logging, optional max-entries cap. Notes appear as a clamped preview under the task title in the dashboard. All stored as plain Roam blocks β fully removed on deconvert.Better Tasks: Enter Focus Mode in the Command Palette. Takes a frozen snapshot of your currently-visible filtered and sorted tasks at entry time, then guides you through one task at a time with progress indicator and keyboard-first controls (j/k navigate, c complete with auto-advance, s/Shift+S snooze +1d/+7d, Enter opens in Roam, r refresh, ? shortcut help, Esc exit). Subtasks appear as a read-only checklist on the parent card and also get their own focus turn. Blocked tasks render with a π hint and disable c to prevent accidental completion. Live pills: metadata refreshes while the queue order stays stable. Stale-queue banner if any queued task is renamed or deleted, with a one-click rebuild.Weekly report for {project} prompt for values at instantiation. Save any existing task as a template via the block context menu, or build one from scratch via Create Better Task template. Instantiate from the Command Palette, the dashboardβs Template button, or programmatically via the Extension Tools API. Date defaults support compact relative syntax (+3d, +1w, +1m) plus the full natural language vocabulary (next Monday, end of month, etc.) and resolve at instantiation time.d key. Always asks for confirmation first (with a subtask-count warning when the task has children), then shows an Undo toast that restores the task exactly as it was β same block refs, metadata, and dependency links. One limitation: a ((block ref)) you typed into ordinary text elsewhere is flattened to plain text by Roam on delete and cannot be brought back by Undo (references managed by Better Tasks β dependencies and explicit subtask links β are cleaned first and fully restored). Also available programmatically via bt_delete / bt_bulk_delete, which require confirm: true.bt_export in the Extension Tools API.buy milk due:friday !high @errands or call dentist tomorrow every week and the task is created with all metadata extracted. Supports due:/start:/defer: date prefixes, !priority, ~energy, p:project, @context, repeat rules, and implicit trailing dates. Runs synchronously before AI; works offline.Shift+G. Summary cards (open/completed/overdue/rate), completion-over-time bar chart, time-to-completion distribution, overdue frequency stats, project breakdown by open count and velocity, recurring task adherence (top/bottom performers), and a 365-day busiest-days heatmap with intensity legend. Period selector (7d/30d/90d/all time). Respects first-day-of-week setting. Lazy computation with 30s cache β no background cost.[text](url)) render as clickable links; [[page refs]] render as clickable tags that navigate to the page (Shift+Click for sidebar).BT_attrParent:: ((uid)) links subtasks across the graph, overriding structural nesting. Progress tracks completion in real time. Extension Tools API includes is_subtask, parent_task_uid, subtask_uids, subtask_progress.BT_attrDepends:: ((uid)). Blocked tasks show a π indicator in pills, dashboard, and Today widget. Circular dependency detection (self, mutual, transitive). Dependency picker in the β― pill menu. Blocked/Actionable filter in dashboard. Auto-unblock on completion; stale dependencies auto-cleaned.Convert an existing TODO
Cursor on a TODO β Command Palette β Convert TODO to Better Task
Or create one from scratch
Command Palette β Create a Better Task
Add scheduling / recurrence
Add a repeat rule (e.g. every Friday) and/or start / defer / due dates.
Better Tasks stores canonical data in child blocks (attribute names configurable; defaults shown).
Write weekly newsletter
- BT_attrRepeat:: every Friday
- BT_attrDue:: [[2025-11-07]]
When completed:
Write weekly newsletter
- BT_attrRepeat:: every Friday
- BT_attrDue:: [[2025-11-07]]
- BT_attrCompleted:: [[2025-10-31]]
Optional attributes:
BT_attrStart:: β when the task becomes availableBT_attrDefer:: β when it should resurfaceBT_attrCompleted:: β written on completionBT_attrNotes:: β freeform notes (user-authored text)BT_attrDepends:: β task dependencies (one or more ((uid)) refs, comma-separated)BT_attrParent:: β explicit subtask link to a parent task (((uid)))β Disable Better Tasks anytime β your tasks remain plain Roam blocks.
Leave the repeat field blank while setting any combination of start::, defer::, or due::.
completed:: [[<today>]] and hides the pill- BT_attrProject:: [[Website Refresh]]
- BT_attrGTD:: Next Action
- BT_attrWaitingFor:: [[Finance Team]]
- BT_attrContext:: @computer, #office
- BT_attrPriority:: high
- BT_attrEnergy:: medium
- BT_attrNotes:: Customer wants this before the demo
- BT_attrDepends:: ((uid1)), ((uid2))
- BT_attrParent:: ((uid))
Metadata appears both inline (pill) and in the dashboard.
Add BT_attrDepends:: ((task-uid)) as a child block to create a dependency. The blocked task shows a π indicator and is dimmed in the dashboard and Today widget.
Nest a Better Task under another Better Task to create a subtask relationship automatically. The parent shows a π progress indicator (e.g. 1/3) inline and in the dashboard.
or block with BT attributes nested directly under another BT task is detected as a subtaskBT_attrParent:: ((parent-uid)) to link a subtask to a parent anywhere in the graph β overrides structural nestingπ done/total in inline pills and dashboardInteractions:
GTD cycles: Next β Delegated β Deferred β Someday β cleared
Priority / Energy cycles: low β medium β high β none
Save reusable task configurations and instantiate them in seconds. A template captures:
{param} placeholders (e.g. Weekly report for {project})Date defaults are stored as relative expressions and resolved at instantiation time. Supported:
+3d, +1w, +2mnext Monday, in 2 weeks, end of month, tomorrow, early next weekParameters use {name} placeholders. Any word works β {project}, {client}, {topic}, {week}, etc. Parameters can be reused across the title and subtask titles, and they can appear inside metadata values too β not just the title.
| Syntax | Meaning |
|---|---|
{client} |
Required parameter β user enters value at instantiation |
{priority:high} |
Parameter with default β pre-fills high, user can override |
{client} reused in multiple places |
Single prompt, value substituted everywhere |
Where parameters can appear:
Sprint review for {team})Gather data from {client}){client} β Engagement)@{location}){stakeholder}){when} β next Monday)Example templates:
| Template title | Other fields | Use case |
|---|---|---|
Weekly report for {project} |
repeat every Friday, priority medium, subtasks Gather data from {project}, Draft report, Review and send |
Recurring deliverable with project-specific subtasks |
1:1 with {person} |
repeat every 2 weeks, context @office, GTD next action |
Routine meetings β one template, many people |
Onboard new {client} |
priority high, project {client} β Engagement, subtasks Send welcome email to {client}, Schedule kickoff with {client}, Prepare {client} brief |
Multi-step workflow parameterised by customer |
Submit {form} to legal |
due +5d, GTD delegated, waiting-for Legal team |
Recurring shape with a different attachment each time |
Investigate {ticket} |
priority high, context @computer, subtasks Reproduce {ticket}, Root cause {ticket}, Write fix and tests |
Bug triage workflow |
Plan {quarter} OKRs |
due end of month, project Strategy, priority high |
Quarterly planning shape |
Creating a template:
Using a template:
{param} values β donebt_create_from_template (Extension Tools API)Managing templates:
Notes:
Common actions:
| Action | Description |
|---|---|
| Snooze +1 day | Shift all existing dates (start/defer/due) forward 1 day |
| Snooze +3 days | Shift all existing dates (start/defer/due) forward 3 days |
| Snooze to next Monday | Shift all existing dates to align with next Monday |
| Snooze (pick date) | Shift all existing dates to align with the picked date |
| Skip this occurrence | Jump to next repeat |
| Generate next now | Create next task immediately |
| End recurrence | Stop repeating |
| Add / Edit dependency | Open dependency picker to search and select blocking tasks |
| Remove all dependencies | Clear all dependencies from the task |
| View series | Open the recurring series timeline (recurring tasks only) |
| Add / Edit notes | Set or edit freeform notes on the task |
| View activity | Open the activity log panel (reverse-chronological event history) |
All actions support Undo.
Snooze logic details:
start::, defer::, or due::, snooze shifts only the dates that exist and preserves spacing between them.defer:: at today + N.Open via Command Palette β Toggle Better Tasks Dashboard or the top-bar icon ![]()
Features:
Shift+G or click Analytics in the header)Shift+I or click Suggestions in the header; see Smart Suggestions below)? in the dashboard for the full legend):| Key | Action |
|---|---|
j / k |
Move focus down / up |
Enter |
Open focused task |
c |
Complete / undo |
s / Shift+S |
Snooze +1d / +7d |
d |
Delete task (confirm dialog; bulk-aware) |
e |
Expand / collapse subtasks |
. |
Open task menu (navigate with j/k/arrows, Enter to select) |
x |
Toggle selection |
Shift+A |
Select all visible |
/ |
Focus search |
f |
Toggle full-page mode |
r |
Refresh |
? |
Show / hide shortcut legend |
Escape |
Close help β clear selection β clear focus |
Customise bindings via JSON in Settings β Advanced Dashboard β Keyboard bindings.
Preset views (seeded, in order):
The review menu (split button in the toolbar) offers four review types:
| Review | Steps |
|---|---|
| Daily | Due Today β Completed Yesterday β Overdue |
| Weekly | Next Actions β Waiting For β Completed 7d β Upcoming 7d β Overdue β Someday |
| Monthly | Completed 30d β Stalled β Someday β Overdue |
| Project Sweep | Select a project β Open β Overdue β Stalled β Completed 30d |
Each step can be independently enabled/disabled per review type in Settings β Advanced Dashboard.
Stalled tasks: open tasks whose block hasnβt been edited in N days (configurable, default 14). Available as a filter chip (Stalled/Active) in the sidebar and as a preset view.
Mobile note:
Apply changes to multiple tasks at once from the dashboard.
Entering bulk mode:
Selecting tasks:
Available actions: | Action | Description | |ββ|ββββ-| | Complete | Mark all selected tasks as done | | Reopen | Revert completed tasks to open | | Snooze +1d | Defer task 1 day | | Snooze +7d | Defer task 7 days | | Project | Set project from picklist | | Waiting For | Set waiting-for from picklist | | Context | Set context from picklist | | Priority | Set to low / medium / high / clear | | Energy | Set to low / medium / high / clear | | GTD | Set to Next Action / Delegated / Deferred / Someday / clear |
All bulk actions support Undo via the toast notification.
Tip: Set up your view first (filters, grouping) before entering bulk mode β this lets you target exactly the tasks you want to update.
A distraction-free, single-task execution surface launched from the Focus button in the dashboard header or via Command Palette β Better Tasks: Enter Focus Mode.
Focus Mode takes a snapshot of your currently-visible filtered and sorted task list at entry time, then guides you through one task at a time. The queue order stays stable for the whole session, but pills, blocked state, and subtask progress update live as you work.
Keyboard shortcuts (capture-phase, isolated from the dashboard):
| Key | Action |
|---|---|
j / n / β |
Next task |
k / p / β |
Previous task |
c |
Complete current task (auto-advances) |
s |
Snooze +1 day |
Shift+S |
Snooze +7 days |
Enter |
Open task in Roam |
r |
Refresh task data (forces a snapshot pull) |
? |
Show / hide shortcut overlay |
Esc |
Exit Focus Mode |
Behaviour:
c is disabled (toast) so you canβt accidentally complete a task whose dependencies arenβt metEsc) to exit; the dashboard returns to wherever you left itTip: set up your filter and sort first (e.g. βDue Todayβ preset, sorted by priority), then click Focus β the queue is built from exactly what you see.
Advisory nudges computed locally from your task history β the extension never changes anything on its own. Open the panel from the Suggestions button in the dashboard header (with a live count badge) or press Shift+I.
| Rule | Fires when | Accept does |
|---|---|---|
| Snoozed task | a task has been snoozed 5+ times (threshold configurable) | moves it to Someday / Maybe |
| Weekday pattern | a recurring series is usually completed on one weekday (5+ completions, 60%+ concentration) but the open occurrence is due on another | reschedules the open occurrence to that weekday |
| Load balancing | a day in the coming week has 4+ tasks due while another day has none | moves one flexible task to the empty day nearest the pile-up |
| Stalled task | an open task hasnβt been edited for N days (default 14, shared with the Stalled filter) and has no near-term due date | moves it to Someday / Maybe |
| Recurring adherence | a series is completed on time 50% of the time or less (5+ dated completions) | opens the repeat-rule editor |
Behaviour:
Also available programmatically via bt_get_suggestions in the Extension Tools API.
Shows tasks starting, deferred until, due, and (optionally) overdue today. Each task row has configurable action buttons:
| Button | Default | Description |
|---|---|---|
| β Complete | On | Mark the task as done |
| β± Snooze +1d | On | Snooze all dates forward 1 day |
| β±+7 Snooze +7d | On | Snooze all dates forward 7 days |
| (()) Copy Ref | Off | Copy the block reference ((uid)) to the clipboard |
| β§ Open Sidebar | Off | Open the task in the right sidebar |
Toggle each button on or off in the Today Widget settings. Clicking a task title navigates to the block; Shift+Click opens it in the sidebar.
Core settings:
[[page links]] so native Roam queries find your tasks; creates pages and linked references for themtask lists β render interactive result lists in blocks containingAdditional sections appear only when enabled.
The quick-add input parses natural language locally using rule-based extraction. No network, no API key, works offline.
Syntax:
| Marker | Example | Writes attribute |
|βββ|βββ|ββββββ|
| due: | due:friday, due:next week | BT_attrDue |
| start: | start:monday, start:in 3 days | BT_attrStart |
| defer: | defer:next month, defer:end of week | BT_attrDefer |
| ! | !high, !medium, !low | BT_attrPriority |
| ~ | ~high, ~medium, ~low | BT_attrEnergy |
| p: | p:ProjectName | BT_attrProject |
| @ | @office, @errands | BT_attrContext |
| Repeat keywords | every friday, daily, weekly | BT_attrRepeat |
| Trailing date | buy milk tomorrow | BT_attrDue (implicit) |
Supported date phrases (for due:, start:, defer:, or trailing):
monday, next tuesday, this fridaytoday, tomorrow, next week, next monthin 3 days, in 2 weeks, 5 days from nowend of week, end of month, end of yearearly next week, mid january, late this month[[April 15th, 2026]], 2026-04-15Examples:
buy milk due:friday β title βbuy milkβ, due Fridaycall dentist tomorrow !high β title βcall dentistβ, due tomorrow, priority highreview PR every week p:Engineering @office β recurring task with project and contextsubmit report end of month β title βsubmit reportβ, due last day of monthplan conference start:monday defer:next month β start Monday, defer next monthsend invoice in 3 days β title βsend invoiceβ, due in 3 daysThe repeat:: attribute accepts natural-language patterns. Parsing is case-insensitive, tolerates extra whitespace, and supports separators like commas, /, &, and the word βandβ.
Abbreviations and ranges are supported (e.g., Mon, Tue, Thu, MWF, TTh, Mon-Fri).
Anchor date: the next occurrence is calculated from due:: (preferred). If no due:: is present, the current date is used as the anchor.
Week start: ranges and some weekly rules respect your First day of the week setting in the extension.
| Example | Meaning |
|β|β|
| every day | daily | once per day |
| every 2 days | every other day | every second day | every 2 days |
| every three days | every 3 days |
| every 5 days | every 5 days |
| every weekday | business days | workdays | Monday-Friday |
| every 2 weekdays | every 2 business days (Mon-Fri cadence) |
| Example | Meaning |
|β|β|
| every monday | every week on Monday |
| every mon | EVERY MON | every MOnDaY | variants accepted |
| Example | Meaning |
|β|β|
| weekly | every week | once per week (no fixed day) |
| every other week | every second week | biweekly | fortnightly | every fortnight | every 2 weeks |
| every 3 weeks | every third week (no fixed day) |
| Example | Meaning |
|β|β|
| weekly on tue, thu | Tuesday and Thursday |
| weekly on tue thu | same (spaces only) |
| weekly on tue & thu | same (& supported) |
| weekly on tue/thu | Tu/Th | t/th | slash shorthand |
| every mon, wed, fri | MWF | Monday, Wednesday, Friday |
| TTh | Tuesday and Thursday |
| weekly on tue, thu and sat & sun | mixed separators supported |
| Example | Meaning |
|β|β|
| every mon-fri | Monday through Friday |
| every fri-sun | Friday to Sunday range |
| every su-tu | Sunday to Tuesday (wrap) |
| Example | Meaning |
|β|β|
| every 2 weeks on monday | every 2nd Monday |
| every 3 weeks on fri | every 3rd Friday |
| every 4 weeks on tue, thu | every 4th week on Tue & Thu |
| every other tuesday | every second tuesday | every 2nd Tuesday (fortnightly) |
| Example | Meaning |
|β|β|
| monthly | same calendar day each month (uses due:: day) |
| every month on day 15 | 15th of each month |
| the 1st day of each month | 1st day every month |
| day 31 of each month | clamps to end of shorter months |
| last day of the month | last day of each month | last day of every month | EOM | last calendar day each month |
| on the 1st and 15th of each month | 1st and 15th |
| on the 15th and last day of each month | 15th + EOM |
| on the 5th, 12th, 20th of each month | on the 5th/12th/20th of each month | on the 5th & 12th & 20th of each month | multiple specific dates |
first monday of each month2nd wed every monthlast friday of each month1st and 3rd monday of each monthpenultimate friday of each month / second last friday ...first weekday of each monthlast weekday of each monthevery month on the second tuesday2nd Tue each monththe last thu each monthevery 2 months on the 10thevery 3 months on the 2nd tuesdayquarterlysemiannual / semi-annually / twice a yearevery March 10, on 10 March every yearannually, yearly (fixed-date anchor)first Monday of May every yearfirst monday of september (the trailing every year is optional)| Example | Meaning |
|β|β|
| every weekend | weekends | Saturday & Sunday |
Notes:
Mon/Mon./Monday, Thu/Thurs/Thursday, MWF, TTh are accepted.Mon-Fri expands to all included days.31st -> Feb 28/29).monday/mondays, week/weeks, etc.Tasks are native Roam blocks with [[page ref]] metadata, so every Roam
query surface can see them β plus a dedicated component for the common case:
Type that in any block and Better Tasks mounts a live task list: native
checkboxes (recurring tasks spawn their next occurrence on completion),
inline pills, a result count and a refresh button. Filters: status,
project, due, completed, blocked, assignee, query (free text),
limit, sort β the same vocabulary as the bt_search API.
More examples:
Native `` and Datalog work too β project, waiting-for and context
values are written as [[page links]], so
}
finds tasks with zero extension involvement.
π Full guide with copy-paste Datalog snippets (overdue, due this week, by project, waiting-for, stalled): docs/query-cookbook.md
Recent versions include memory and render optimisations.
If Roam feels slow:
Supported:
UI is fully locale-aware.
Natural-language recurrence parsing is intentionally English-only for now.
Better Tasks registers tools on window.RoamExtensionTools["better-tasks"] so other extensions (e.g. Chief of Staff) can query and manage tasks programmatically.
| Tool | Description |
|---|---|
bt_get_projects |
List projects with derived status and optional task counts |
bt_get_waiting_for |
List waiting-for values with optional counts |
bt_get_context |
List context values with optional counts |
bt_get_attributes |
Get configured attribute schema β all 14 attributes with names, types, aliases, and allowed values |
bt_search |
Search tasks by status, due, project, assignee, blocked state, or free text. Results include is_subtask, parent_task_uid, subtask_uids, subtask_progress. |
bt_create |
Create a new task (defaults to todayβs daily page). Supports all attributes including parent and depends. |
bt_modify |
Update an existing taskβs status, text, or attributes |
bt_bulk_modify |
Modify multiple tasks in a single operation (max 50) |
bt_bulk_snooze |
Snooze multiple tasks by shifting defer/start/due dates forward |
bt_delete |
Permanently delete a task and its entire subtree; cleans dependency/parent references first. Requires confirm: true. |
bt_bulk_delete |
Delete multiple tasks in one operation (max 50). Requires confirm: true. |
bt_get_analytics |
Task analytics: overdue count, completion rate, velocity by project and time period |
bt_get_analytics_detailed |
Full analytics: summary, completion over time, time-to-completion distribution, overdue frequency, project breakdown, recurring adherence, busiest-days heatmap |
bt_get_suggestions |
Advisory suggestions from local heuristics: snooze counts, weekday patterns, load balancing, stalled tasks, recurring adherence. Read-only. |
bt_get_task_by_uid |
Fetch a single task by its block UID with full details |
bt_export |
Export tasks as JSON, CSV, or ICS with optional status/project filters (returns data, no browser download) |
bt_list_templates |
List saved task templates with their parameters |
bt_create_from_template |
Create a task from a saved template; resolves parameters and creates subtasks |
bt_manage_templates |
Create, update, delete, or duplicate templates programmatically |
bt_search blocked filter values| Value | Meaning |
|---|---|
blocked |
Only tasks blocked by incomplete dependencies |
actionable |
Only tasks not blocked (no deps or all deps complete) |
bt_search due filter values| Value | Meaning |
|---|---|
overdue |
TODO tasks past their due date |
today |
Tasks due today |
this-week |
Tasks due after today through 7 days from now (use today for todayβs tasks) |
upcoming |
Tasks due in the future (not overdue or today) |
none |
Tasks with no due date |
ISO date (e.g. 2026-02-20) |
Tasks due on that specific date |
bt_get_projects derives status from task counts rather than a stored field:
Enjoy Better Task management directly inside Roam Research!