Files
Lumotia/docs/architecture-map/02-tauri-runtime/commands/tasks.md
jars a1f3f3f134 docs: architecture map (initial 5-slice generation, 105 pages)
Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:

  01-frontend (16)              Svelte/SvelteKit UI
  02-tauri-runtime (26)         src-tauri commands + lifecycle
  03-audio-transcription (16)   audio + transcription crates
  04-llm-formatting-mcp (19)    llm, ai-formatting, mcp, cloud
  05-core-storage-hotkey-build  core, storage, hotkey, workspace,
                          (26) CI, dev glue

Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.

Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.

Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:04:13 +01:00

8.0 KiB
Raw Blame History

name, type, slice, last_verified
name type slice last_verified
Tasks and decomposition architecture-map-page 02-tauri-runtime 2026/05/09

commands::tasks

Where you are: Architecture mapTauri runtimeCommands → Tasks

Plain English summary. Eleven commands wrapping the magnotia_storage task CRUD plus two LLM-driven actions. Standard CRUD: create / list / update / complete / uncomplete / delete a task, plus subtask CRUD (insert / list / complete) and a daily-completion-counts query for the Phase 8 Tasks-page momentum sparkline. The two LLM actions: decompose_and_store (break a parent task into subtasks via the local LLM with HITL feedback as few-shot exemplars) and extract_tasks_from_transcript_cmd (extract task lines from a recently-finished transcript, again with feedback exemplars).

At a glance

  • Path: src-tauri/src/commands/tasks.rs.
  • LOC: 402.
  • Tauri commands exposed (11 total):
    • create_task_cmd(state, request: CreateTaskRequest) -> Result<TaskDto, String>.
    • list_tasks_cmd(state) -> Result<Vec<TaskDto>, String>.
    • update_task_cmd(state, id, patch: UpdateTaskRequest) -> Result<TaskDto, String>. Patch shape (text / bucket / list_id / effort / notes).
    • complete_task_cmd(state, id) -> Result<(), String>. Stamps server-side done_at.
    • delete_task_cmd(state, id) -> Result<(), String>.
    • uncomplete_task_cmd(state, id) -> Result<(), String>. Clears done_at.
    • set_task_energy_cmd(state, id, energy: Option<String>) -> Result<TaskDto, String>. Always writes; passes None to clear.
    • decompose_and_store(state, parent_task_id, profile_id) -> Result<Vec<TaskDto>, String>.
    • extract_tasks_from_transcript_cmd(state, transcript, profile_id) -> Result<Vec<String>, String>.
    • list_subtasks_cmd(state, parent_task_id) -> Result<Vec<TaskDto>, String>.
    • complete_subtask_cmd(state, subtask_id) -> Result<(), String>.
    • list_recent_completions_cmd(state, days) -> Result<Vec<DailyCompletionCount>, String>.
  • Events emitted: none.
  • Depends on: magnotia_storage::{insert_task, list_tasks, update_task, complete_task, uncomplete_task, delete_task, set_task_energy, get_task_by_id, insert_subtask, list_subtasks, complete_subtask_and_check_parent, list_recent_completions, list_feedback_examples, FeedbackTargetType, TaskRow, DailyCompletionCount, FeedbackRow}, magnotia_llm::prompts::FeedbackExample, uuid::Uuid.
  • Called from frontend at: Tasks page (CRUD, subtasks, sparkline), dictation result panel ("Extract tasks" button), parent-task expand UI ("Decompose").

What's in here

TaskDto (src-tauri/src/commands/tasks.rs:24)

camelCase frontend shape with id, text, bucket, listId, effort, notes, done, doneAt, createdAt, sourceTranscriptId, parentTaskId, energy.

Energy validation (:60)

ENERGY_LEVELS = ["high", "medium", "brain_dead"] — kept as a const so frontend and storage validate against the same set. SQLite migration v11 enforces the same set with a CHECK constraint.

CRUD wrappers

  • create_task_cmd (:92) inserts and re-fetches so the frontend gets the canonical row (server-side timestamps, defaulted columns).
  • update_task_cmd (:140) — patch shape, COALESCE-style updates in storage. done / doneAt are deliberately absent — those flow through complete_task_cmd / uncomplete_task_cmd.
  • set_task_energy_cmd (:200) — separate from update because update uses COALESCE semantics where None means "preserve". This command always writes, so passing None actually clears the column.

to_llm_examples (:222)

Converts feedback rows from storage into the few-shot exemplar shape the LLM crate consumes. Reconstructs input from context_json (parent task text or transcript chunk). Rows with malformed context_json are logged and dropped instead of silently filtered, so data-integrity regressions surface.

example_char_cost (:263) and trim_to_budget (:276)

Char budget for the few-shot exemplars: keeps the prompt under token budget regardless of how many feedback rows the user has accumulated. Cap at 5 examples AND a char budget.

decompose_and_store (:290)

  1. Fetch the parent task or 404.
  2. Pull up to 5 micro-step feedback exemplars filtered by profile, char-trimmed.
  3. spawn_blocking runs engine.decompose_task_with_feedback(parent_text, &examples).
  4. Insert each generated step as a subtask (uuid::v4() for the id), re-fetch, accumulate.
  5. Return the list.

NO PowerAssertion::begin here — the App Nap pattern is consistent in commands::llm but not yet uniformly applied here. Flag for follow-up.

extract_tasks_from_transcript_cmd (:345)

Same shape as decompose_and_store but with FeedbackTargetType::TaskExtraction and the engine's extract_tasks_with_feedback. Returns the raw task strings — the frontend decides whether to insert them.

list_subtasks_cmd / complete_subtask_cmd (:370, :381)

complete_subtask_cmd calls complete_subtask_and_check_parent which is the storage helper that stamps the subtask done and, if all siblings are done, also stamps the parent (Phase 8 micro-completion bookkeeping).

list_recent_completions_cmd (:394)

Fixed-length oldest-first daily counts. Empty days are explicit zeros. The Tasks-page sparkline reads this directly.

Data flow

Tasks page mount -> list_tasks_cmd -> [TaskDto, ...]
Tasks page create -> create_task_cmd(req) -> TaskDto
Tasks page edit -> update_task_cmd(id, patch) -> TaskDto
Tasks page check -> complete_task_cmd(id) -> ()
Tasks page reopen -> uncomplete_task_cmd(id) -> ()
Tasks page energy chip -> set_task_energy_cmd(id, energy) -> TaskDto
Tasks page sparkline -> list_recent_completions_cmd(days) -> [{date, count}, ...]

Tasks page Decompose button -> decompose_and_store(parent_id, profile_id)
  -> get parent task
  -> list 5 micro-step feedback rows (profile-scoped)
  -> trim_to_budget
  -> spawn_blocking(engine.decompose_task_with_feedback)
  -> insert subtasks
  -> [TaskDto, ...]

Dictation panel Extract tasks -> extract_tasks_from_transcript_cmd(text, profile_id)
  -> list 5 task-extraction feedback rows
  -> spawn_blocking(engine.extract_tasks_with_feedback)
  -> [String, ...]

Watch-outs

  • No ensure_main_window guard. Tasks UI lives in the main window AND in the always-on-top task float (which has the secondary-windows capability). The float can call list / complete / set-energy / list-recent-completions etc. — that's intentional — but it can also fire decompose_and_store and extract_tasks_from_transcript_cmd, which spend LLM tokens. If you want to lock this down, add the guard to the LLM-spending commands.
  • No PowerAssertion. decompose_and_store and extract_tasks_from_transcript_cmd both run synchronous LLM inference for several seconds. macOS can App Nap them. Add PowerAssertion::begin("magnotia LLM task decomposition") and similar.
  • The patch shape passes Option<String> for every column. Currently the storage layer's update_task uses COALESCE: Some overwrites, None preserves. This means there's no way to clear notes or effort to empty via update_task_cmd — you can only set them to a non-empty string. If a user wants to clear a field, they'd need a fresh task or a dedicated clear command.
  • Decompose stores subtasks one-by-one in a loop (:329). Each iteration is a separate DB transaction. Acceptable for typical 37-step decompositions; if a future LLM produces 50 steps, batch the inserts.
  • extract_tasks_from_transcript_cmd returns just Vec<String> and does NOT insert. Frontend chooses what to insert. Confusing because the sibling decompose_and_store does insert. Convention is dictated by UX (decomposition is one-click, extraction reviews-then-inserts).

See also

  • LLM — the engine that runs the decomposition / extraction.
  • Feedback — the table that feeds the few-shot exemplars.
  • Profilesprofile_id is the scoping key for feedback rows.
  • Window management — the task-float window (tasks-float) that consumes list_tasks_cmd.