Motivation
People write todos as markdown checkboxes — that muscle memory is the whole point. The
schema system's Task type covers a note that is a task; this is the complementary case:
one note containing many tasks ("find the todos in note X", meeting notes with action
items, a note used as a kanban board). Today checkbox lines are invisible to the graph
(deliberately excluded from observations), and the extended markers actually leak as junk
categories (#1241).
Design discussion origin: PR #1239 review conversation. Observations were considered and
rejected as the container: they'd conflate parser-derived state with user hashtags,
pollute context assembly with stale done-items, and create a second task system beside the
schema Task type. Tasks deserve their own row kind.
Proposed shape
New derived table task_item, the observation table's sibling:
task_item:
project_id, entity_id (FK CASCADE) -- per-note scope
content -- text after the marker
marker -- raw char ('x', '/', '-', ' ', ...), fidelity/round-trip
state -- derived: open | done | in_progress | cancelled | other
section -- nearest heading (the kanban lane; pairs with #547)
ordinal -- position in note (card order)
Marker semantics — follow prior art exactly
- GFM baseline (GitHub renders these):
[ ] open, [x]/[X] done.
- Obsidian Tasks / community convention (de-facto standard beyond GFM):
[/] =
in progress, [-] = cancelled/dropped, [>] = deferred, [?] = question.
- Derive only the well-attested states (open / done / in_progress / cancelled); everything
else is state=other with the raw marker preserved. Never invent semantics.
Kanban
The Obsidian Kanban plugin's model is lanes = ## headings, cards = list items, done =
lane membership or checkbox. The section column is what makes a note kanban-queryable
(group tasks by section; move a card = edit_note section operation). This pairs directly
with #547 (header indexing) — landing heading context once serves section validation,
deep-linking, and kanban lanes together.
Scope guards
Refs: #1241 (interim marker exclusion), #547 (header indexing), #1219/#1239 (observation
false-positive lineage), memory-tasks skill / schema Task type (note-granularity tasks).
Motivation
People write todos as markdown checkboxes — that muscle memory is the whole point. The
schema system's Task type covers a note that is a task; this is the complementary case:
one note containing many tasks ("find the todos in note X", meeting notes with action
items, a note used as a kanban board). Today checkbox lines are invisible to the graph
(deliberately excluded from observations), and the extended markers actually leak as junk
categories (#1241).
Design discussion origin: PR #1239 review conversation. Observations were considered and
rejected as the container: they'd conflate parser-derived state with user hashtags,
pollute context assembly with stale done-items, and create a second task system beside the
schema Task type. Tasks deserve their own row kind.
Proposed shape
New derived table
task_item, the observation table's sibling:search_indexrows of typetask→ "todos in note X" is the existing search surfacewith
--entity-type taskscoped to a note;read_note --jsongainstasks[].post-commit publication path as observations/relations (Generation-versioned observation persistence (companion to relation deadlock fix) #1214 machinery; AGENTS.md
consistency doctrine applies — eventually consistent, stale writers no-op).
Marker semantics — follow prior art exactly
[ ]open,[x]/[X]done.[/]=in progress,
[-]= cancelled/dropped,[>]= deferred,[?]= question.else is
state=otherwith the raw marker preserved. Never invent semantics.Kanban
The Obsidian Kanban plugin's model is lanes =
##headings, cards = list items, done =lane membership or checkbox. The
sectioncolumn is what makes a note kanban-queryable(group tasks by section; move a card =
edit_notesection operation). This pairs directlywith #547 (header indexing) — landing heading context once serves section validation,
deep-linking, and kanban lanes together.
Scope guards
(e.g. exclude captured/imported directories) rather than a parse-time guess about intent.
Refs: #1241 (interim marker exclusion), #547 (header indexing), #1219/#1239 (observation
false-positive lineage), memory-tasks skill / schema Task type (note-granularity tasks).