Skip to content

Obsidian Tasks support: date-aware, filterable task index (phased) #751

Description

@srid

Summary

Make Emanote's task index (/-/tasks) a date-aware, filterable dashboard by understanding Obsidian Tasks emoji syntax. Tasks stay authored inline in their notes (- [ ] …); only the rendering gets smarter. Emanote stays read-only — completing/rolling tasks is the editor's job; Emanote displays.

Motivating use case: a calm, pull-not-push daily task dashboard (GTD "open loops" style) — a view you open, never a nag.

Authoring syntax (target)

Standard Obsidian Tasks emoji, appended to any - [ ] line:

- [ ] Draft the release notes 📅 2026-07-03 #active
- [ ] Follow up with the vendor ⏳ 2026-12-01 🔼 #waiting
- [ ] Send the monthly report 📅 2026-07-21 🔁 every month #active
Emoji Meaning Phase
📅 due · scheduled · 🛫 start dates 1
created · done · cancelled dates 1
🔺⏫🔼🔽⏬ priority 3
🔁 recurrence rule 3
🆔 / id / depends-on later

Task "state" (e.g. active/waiting/held/someday for a loop workflow) is just a #tag — already supported, no new syntax. Hierarchical tags (#loop/active, #loop/held, …) are recommended so related states share a namespace and filter as a group (loop/*).

Current behaviour (baseline)

/-/tasks (View/TaskIndex.hs) lists unchecked tasks, grouped by note, in path order; no dates, no filtering. Emoji/dates render as literal text. Tasks can't be filtered by tag (a task's inline #tag tags the note, not the task). This proposal changes that.


Phase 1 — Show task dates (PR 1)

You get: every task on /-/tasks shows its due/scheduled date as a badge, with overdue in red and due-today highlighted (computed live from the browser clock, so it never goes stale on the static site).

  • Parse the date emoji from each task's inlines into the task model (_taskDueDate, _taskScheduled, …); strip the recognised tokens from the rendered text and emit badges instead.
  • Parse in Emanote's task layer (Model/Task.hs) — no change to the heist-extra parser needed.
  • Template emits data-due etc.; a tiny vanilla loops.js adds the overdue/today classes. JS-off still shows the plain list.

Phase 2 — Filter & sort dashboard (PR 2)

You get: /-/tasks becomes a real dashboard — filter by tag (hierarchical, so namespaced states filter individually or as foo/*) and by due window (overdue · next 3 days · all), sort by due, and toggle group-by-note ⇄ a flat agenda. Default view = "what needs me soon."

  • Emit data-tags per task; client-side controls do the filtering/sorting (no rebuild).
  • A small load count ("12 open · 3 due") for at-a-glance load.

Phase 3 — Priority & recurrence (PR 3)

You get: priority badges (/🔼/🔽) that sort, and recurring tasks (🔁) shown with their rule and a computed next due.

  • Parse priority + recurrence; extend sort to (overdue, priority, due).
  • Recurrence is display only — Emanote doesn't mutate files.

Phase 4 — Embedded task queries (PR 4)

You get: drop a query into any note to embed a filtered task list — e.g. a hand-made dashboard page showing "all #active due this week." Composability beyond the global /-/tasks.

  • Extend the query mechanism (Model/Query.hs, currently note-only) with a tasks source + a render template, reusing the Phase 1–3 parsing.

Non-goals

  • Reminders / push. Pull-not-push — a view you open, not a nag. No notifications, no server.
  • Editing/completing tasks. Emanote renders; an editor (or external tooling) mutates the Markdown.

Key files

heist-extra:TaskList.hs (low-level parse) · Model/Task.hs (indexed task + new metadata) · View/TaskIndex.hs + templates/special/tasks.tpl (the view) · Model/Query.hs (Phase 4) · new default/js/loops.js.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions