core / planning.py

Hierarchical task tree with dependency types, postcondition gating, alternatives, and revision tracking.

Data model

TypeVariants / fields
TaskStatus enum (line 9)PENDING · READY · IN_PROGRESS · DONE · FAILED · BLOCKED · PAUSED · NEEDS_USER
DependencyType enum (line 24)ALL — every child must succeed · ANY — first success satisfies parent · BEST — run all, pick best
TaskNode (line 32)id, description, status, parent_id, children, dependency_type, alternatives, postconditions, estimated_cost, actual_cost, revision_count, result_summary, failure_reason, actual_tool_used, depth, position

Methods

MethodEffect
add_task(description, parent_id, status, dependency_type, alternatives, postconditions)Insert task, return id (line 60).
update_status(task_id, status, result, failure_reason, actual_tool)Mark transition; trigger postcondition check + parent propagation (line 89).
_check_postconditions(node)≥60 % token-overlap heuristic between result_summary and each postcondition; optional custom checker callback (line 120).
_check_parent_completion(parent_id)ALL/ANY/BEST aggregation propagated upward (line 165).
_check_parent_failure(parent_id)Spawns alternatives, propagates BLOCKED/FAILED (line 216).
get_active_node()Next leaf in IN_PROGRESS or READY (line 267).
render()ASCII tree with emoji status icons (line 292).
request_revision(task_id, failure_reason)Increment revision_count, reset to PENDING if <3 (line 394).
load_from_json(json_data)Stateful merge (no clear) so concurrent edits survive.

Example tree

root: ship feature X DependencyType=ALL design schema DONE ✓ implement endpoint IN_PROGRESS · revision 1 smoke test PENDING (blocked) add database column DONE wire route handler READY alt: in-memory cache impl alternative — fires if main fails

Figure 4 — Hierarchical decomposition with dependencies, alternatives, and propagation.

Postcondition matching

Token overlap ≥ 60 % case-insensitive, with stop words filtered ({the, and, for, not, are, has}). A postcondition prefixed with HUMAN_GATE: is special-cased by project_safety to flip the task to NEEDS_USER regardless of tool output.

ProjectPlan

Same shape as TaskTree but persisted via memory.projects's SQLite store. ProjectPlan.update_status() wraps TaskTree.update_status() with a write-through to the database.

Concurrency

Synchronous tree mutation. Persistence happens via the ProjectStore RLock; in-memory TaskTree is per-request only.