tx

PRD-002: Hierarchical Task Structure

Flexible N-level task nesting for natural decomposition from high-level goals to atomic work items

Status: Draft Priority: P0 (Must Have) Owner: TBD Last Updated: 2025-01-28


Problem Statement

Existing agent task systems treat all tasks as flat lists or force a rigid hierarchy (Epic → Story → Task). Real work doesn't fit these models:

  1. Flat lists lose context - which tasks belong together?
  2. Fixed hierarchies are too rigid - sometimes you need 2 levels, sometimes 5
  3. Git worktrees per task (beads approach) is heavyweight for subtasks

We need flexible N-level nesting where any task can have children, enabling natural decomposition from high-level goals to atomic work items.


Use Cases

Case 1: Feature Development

Epic: Implement user authentication (tx-001)
├── Milestone: Backend auth complete (tx-002)
│   ├── Task: Design auth schema (tx-003)
│   ├── Task: Implement JWT service (tx-004)
│   │   ├── Subtask: Add token generation (tx-005)
│   │   ├── Subtask: Add token validation (tx-006)
│   │   └── Subtask: Add refresh logic (tx-007)
│   └── Task: Write auth middleware (tx-008)
└── Milestone: Frontend auth complete (tx-009)
    ├── Task: Build login form (tx-010)
    └── Task: Add auth context (tx-011)

Case 2: Bug Investigation

Bug: Users can't log in (tx-100)
├── Investigation: Check auth service logs (tx-101)
├── Investigation: Test JWT expiry (tx-102)
└── Fix: Update token refresh (tx-103) [blocked by tx-101, tx-102]

Case 3: Agent Decomposition

An agent receives: "Add dark mode to the app"

Task: Add dark mode (tx-200)
├── Subtask: Research existing theme system (tx-201) [created by agent]
├── Subtask: Add theme toggle component (tx-202) [created by agent]
├── Subtask: Update CSS variables (tx-203) [created by agent]
└── Subtask: Test in all views (tx-204) [created by agent]

Requirements

Hierarchy Operations

IDRequirementCLI Command
H-001Any task can have a parent_id pointing to another tasktx add "Task" --parent=<id>
H-002No limit on nesting depthN/A (architectural)
H-003Get all children of a task (direct)tx children <id>
H-004Get all descendants (recursive subtree)tx tree <id>
H-005Get all ancestors of a task (path to root)tx path <id>
H-006Move task to different parenttx update <id> --parent=<new-parent>
H-007Orphan detection (parent deleted but children remain)tx list --orphaned

Hierarchy Queries

QueryCommandOutput
List direct childrentx children <id>Task list
Show full subtreetx tree <id>Tree visualization
List root taskstx list --rootsTasks with no parent
Show ancestorstx path <id>Path from task to root

Constraints

IDConstraintEnforcement
C-001Circular reference prevention (A → B → A)Validation on update
C-002Parent must exist when setting parent_idForeign key + validation
C-003Deleting parent orphans children (default)ON DELETE SET NULL
C-004Cascade delete available via flagtx delete <id> --cascade

Design Decisions

DecisionChoiceRationale
Hierarchy storageparent_id columnSimple, queryable, matches Effect Schema
Recursive queriesApplication-levelSQLite recursive CTEs are complex; iterate in code
Delete behaviorOrphan by defaultCascade is dangerous; explicit cleanup preferred
Depth trackingComputed at query timeAvoids maintenance overhead

API Examples

Create Subtask

# Create a child task
tx add "Implement token validation" --parent=tx-a1b2c3

# Create with score
tx add "Write unit tests" --parent=tx-a1b2c3 --score=600

View Hierarchy

# Show tree
$ tx tree tx-a1b2c3
tx-a1b2c3: Implement JWT service [active]
├── tx-d4e5f6: Add token generation [done]
├── tx-g7h8i9: Add token validation [active]
└── tx-j0k1l2: Add refresh logic [ready]

# Show path to root
$ tx path tx-g7h8i9
tx-g7h8i9 tx-a1b2c3 tx-m3n4o5 (root)

Move Task

# Move to new parent
tx update tx-g7h8i9 --parent=tx-newparent

# Make root task (remove parent)
tx update tx-g7h8i9 --parent=null

Data Model

// Parent-child relationship via parent_id
interface Task {
  id: TaskId
  parentId: TaskId | null  // null = root task
  // ... other fields
}

// Query result with children populated
interface TaskWithDeps {
  // ... task fields
  children: TaskId[]  // Direct child IDs
}

On this page