Tasks as First-Class Entities
Why tasks are separate from notes
Many note-taking apps treat tasks as checkboxes embedded in notes. This works for simple to-do lists but breaks down when you need project management: you cannot easily filter, sort, or view tasks across multiple notes.
NoteCove stores tasks as independent entities in their own directory ({SD}/tasks/). This gives tasks their own metadata (state, priority, type, project, relationships) without bloating the note schema, and lets the app build specialized views (Kanban boards, filtered lists) that would be impossible if tasks were trapped inside note content.
| Notes | Tasks | |
|---|---|---|
| Storage | {SD}/notes/ | {SD}/tasks/ |
| Sync | Independent stream | Independent stream |
| Metadata | Title, folder, pinned | Title, folder, pinned, state, priority, type, project |
| Views | List, search | Kanban, list, search, filters |
| Relationships | Links to other notes | Parent, blocker, discovered-from |
The trade-off is that tasks and notes are connected by reference (task links in notes, [[T:PROJ-42]]) rather than embedded. In practice this is more powerful — a task can be referenced from multiple notes, and its state updates everywhere it appears.
The project model
Tasks are organized into projects. Each project has:
- A slug prefix (e.g.,
PROJ) — tasks get IDs likePROJ-1,PROJ-2 - Custom workflow states — define your own pipeline (Backlog → In Progress → Review → Done)
- Custom types — categorize tasks (Bug, Feature, Chore)
- Multiple boards — different Kanban views with different filters
Projects can be archived (soft-deleted) when no longer active, and purged (permanently deleted along with all their tasks) when you want to reclaim the slug prefix.
Task relationships
Parent-child
Break a large task into subtasks. The parent shows a child count badge. Subtasks inherit the parent’s project but have their own state and priority.
Blockers
Mark one task as blocking another. Blocked tasks show a warning badge. The notecove task ready CLI command filters to tasks with no uncompleted blockers — useful for finding what to work on next.
Discovered-from
When working on task A reveals the need for task B, link B as “discovered from” A. This preserves the context of why a task was created without cluttering the parent-child hierarchy.
Slug system
Each task gets a unique slug in the format {PREFIX}-{SHORT_ID} (e.g., PROJ-a5f). Slugs are:
- Stable — they do not change when a task moves between states or folders
- Searchable — type a slug in search to jump to a task instantly
- Linkable — embed slugs in notes with
[[T:PROJ-a5f]]
When a task is moved to a different project, it gets a new slug in the destination project. Existing links continue working because they reference the task by internal ID, not slug.
CRDT sync
Tasks use the same CRDT sync mechanism as notes — each task is its own Yjs document, stored as update files in the storage directory. Task changes sync across devices the same way note changes do, with the same conflict-free guarantees.