Skip to content

Latest commit

 

History

History
55 lines (43 loc) · 2.52 KB

File metadata and controls

55 lines (43 loc) · 2.52 KB

Per-thread task board (kanban todos)

graph::todos gives a graph a per-thread task board: an ordered list of task cards with a small kanban lifecycle. It is the concrete-work-items counterpart to the single-objective graph::goals, a provider-neutral port of OpenHuman's task board / todos modules.

See the source module README at src/graph/todos/README.md for the full public surface; this spec captures the design contract.

Model

  • TaskBoardCard { id, title, status, objective, plan, assigned_agent, allowed_tools, approval_mode, acceptance_criteria, evidence, notes, blocker, session_thread_id, source_metadata, order, updated_at }.
  • TaskCardStatus: Todo, AwaitingApproval, Ready, InProgress, Blocked, Done, Rejected. TaskApprovalMode: Required, NotRequired.
  • TaskBoard { thread_id, cards, updated_at }; TodosSnapshot (cards + markdown) is returned by every CRUD op.
  • render_markdown renders GitHub-flavored markers ([ ]/[x]/[~]/[!]/[?]/[-]) with indented metadata; parse_status accepts aliases; normalise_board generates ids, trims, drops empty-title cards, backfills a blocker from notes, and recomputes order.

Persistence

One serialized TaskBoard per thread in the graph.todos namespace of a harness::store::Store, keyed by hex(thread_id). Each mutation runs load → mutate → normalise → put under a per-thread async mutex (atomic within one process, same caveat as graph::goals).

Invariants

  • Single in-progress: at most one card may be InProgress; a violation is a Validation error on add / edit / replace / claim_card — never silently fixed.
  • decide_plan only transitions an AwaitingApproval card; a stale decision errors. revise_plan rejects all awaiting cards and is a lenient no-op when none awaits.
  • claim_card is an atomic compare-and-set: transition from one of expected to target under the lock, else reject.

Tool

TodoTool is a single multiplexer harness Tool dispatching on an op field (add/edit/update_status/decide_plan/revise_plan/remove/replace/ clear/list), built with todo_tools / register_todo_tools. The board is bound to ToolExecutionContext::thread_id (never a tool argument). Domain errors (unknown id, invariant violation) are surfaced to the model as tool errors rather than failing the run.

Testing

Unit tests in src/graph/todos/test.rs (types, store invariants, tool); an end-to-end model-driven tool run in tests/e2e_graph_todos.rs.