# Tasks Module

Beads-inspired task management optimized for multi-agent coordination. Unlike beads (Git-distributed JSONL), this uses centralized SQLite for simplicity since all agents share the same workspace.

## Design Rationale

### Why Not Just Use Beads?

Beads solves a different problem: distributed task tracking across forked repos with zero coordination. We don't need that:

- All Workers operate in the same workspace under one `cw` server
- SQLite is the single source of truth
- tRPC exposes task queries directly to agents and dashboard
- No merge conflicts, no Git overhead

### Core Agent Problem Solved

Agents need to answer: **"What should I work on next?"**

The `ready` query solves this: tasks that are `open` with all dependencies `closed`. Combined with priority ordering, agents can self-coordinate without human intervention.

---

## Data Model

### Task Entity

| Field | Type | Description |
|-------|------|-------------|
| `id` | TEXT | Primary key. Hash-based (e.g., `tsk-a1b2c3`) or UUID |
| `parent_id` | TEXT | Optional. References parent task for hierarchies |
| `initiative_id` | TEXT | Optional. Links to Initiatives module |
| `phase_id` | TEXT | Optional. Links to initiative phase (for grouped approval) |
| `project_id` | TEXT | Optional. Scopes task to a project |
| `title` | TEXT | Required. Short task name |
| `description` | TEXT | Optional. Markdown-formatted details |
| `type` | TEXT | `task` (default), `epic`, `subtask` |
| `status` | TEXT | `open`, `in_progress`, `blocked`, `closed` |
| `priority` | INTEGER | 0=critical, 1=high, 2=normal (default), 3=low |
| `assigned_to` | TEXT | Agent/worker ID currently working on this |
| `assigned_at` | INTEGER | Unix timestamp when assigned |
| `metadata` | TEXT | JSON blob for extensibility |
| `created_at` | INTEGER | Unix timestamp |
| `updated_at` | INTEGER | Unix timestamp |
| `closed_at` | INTEGER | Unix timestamp when closed |
| `closed_reason` | TEXT | Why/how the task was completed |

### Task Dependencies

| Field | Type | Description |
|-------|------|-------------|
| `task_id` | TEXT | The task that is blocked |
| `depends_on` | TEXT | The task that must complete first |
| `type` | TEXT | `blocks` (default), `related` |

### Task History

| Field | Type | Description |
|-------|------|-------------|
| `id` | INTEGER | Auto-increment primary key |
| `task_id` | TEXT | The task that changed |
| `field` | TEXT | Which field changed |
| `old_value` | TEXT | Previous value |
| `new_value` | TEXT | New value |
| `changed_by` | TEXT | Agent/user ID |
| `changed_at` | INTEGER | Unix timestamp |

---

## SQLite Schema

```sql
CREATE TABLE tasks (
  id TEXT PRIMARY KEY,
  parent_id TEXT REFERENCES tasks(id),
  initiative_id TEXT,
  phase_id TEXT,
  project_id TEXT,

  title TEXT NOT NULL,
  description TEXT,
  type TEXT NOT NULL DEFAULT 'task' CHECK (type IN ('task', 'epic', 'subtask')),

  status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'in_progress', 'blocked', 'closed')),
  priority INTEGER NOT NULL DEFAULT 2 CHECK (priority BETWEEN 0 AND 3),

  assigned_to TEXT,
  assigned_at INTEGER,

  metadata TEXT,

  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
  updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
  closed_at INTEGER,
  closed_reason TEXT
);

CREATE TABLE task_dependencies (
  task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
  depends_on TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
  type TEXT NOT NULL DEFAULT 'blocks' CHECK (type IN ('blocks', 'related')),
  PRIMARY KEY (task_id, depends_on),
  CHECK (task_id != depends_on)
);

CREATE TABLE task_history (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
  field TEXT NOT NULL,
  old_value TEXT,
  new_value TEXT,
  changed_by TEXT,
  changed_at INTEGER NOT NULL DEFAULT (unixepoch())
);

CREATE INDEX idx_tasks_status ON tasks(status);
CREATE INDEX idx_tasks_priority ON tasks(priority);
CREATE INDEX idx_tasks_assigned ON tasks(assigned_to);
CREATE INDEX idx_tasks_project ON tasks(project_id);
CREATE INDEX idx_tasks_initiative ON tasks(initiative_id);
CREATE INDEX idx_tasks_phase ON tasks(phase_id);
CREATE INDEX idx_task_history_task ON task_history(task_id);

-- The critical view for agent work discovery
-- Tasks are ready when: open, no blocking deps, and phase approved (if linked)
CREATE VIEW ready_tasks AS
SELECT t.* FROM tasks t
LEFT JOIN initiative_phases p ON t.phase_id = p.id
WHERE t.status = 'open'
  AND (t.phase_id IS NULL OR p.status IN ('approved', 'in_progress'))
  AND NOT EXISTS (
    SELECT 1 FROM task_dependencies d
    JOIN tasks dep ON d.depends_on = dep.id
    WHERE d.task_id = t.id
      AND d.type = 'blocks'
      AND dep.status != 'closed'
  )
ORDER BY t.priority ASC, t.created_at ASC;
```

---

## Status Workflow

```
     ┌──────────────────────────────────────┐
     │                                      │
     ▼                                      │
  [open] ──claim──▶ [in_progress] ──done──▶ [closed]
     │                    │
     │                    │ blocked
     │                    ▼
     └───────────── [blocked] ◀─────unblock───┘
```

| Transition | Trigger | Notes |
|------------|---------|-------|
| `open` → `in_progress` | Agent claims task | Sets `assigned_to`, `assigned_at` |
| `in_progress` → `closed` | Work completed | Sets `closed_at`, `closed_reason` |
| `in_progress` → `blocked` | External dependency | Manual or auto-detected |
| `blocked` → `open` | Blocker resolved | Clears assignment |
| `open` → `closed` | Cancelled/won't do | Direct close without work |

---

## CLI Reference

All commands under `cw task` subcommand.

### Core Commands

| Command | Description |
|---------|-------------|
| `cw task ready` | List tasks ready for work (open + no blockers) |
| `cw task list [--status STATUS] [--project ID]` | List tasks with filters |
| `cw task show <id>` | Show task details + history |
| `cw task create <title> [-p PRIORITY] [-d DESC]` | Create new task |
| `cw task update <id> [--status STATUS] [--priority P]` | Update task fields |
| `cw task close <id> [--reason REASON]` | Mark task complete |

### Dependency Commands

| Command | Description |
|---------|-------------|
| `cw task dep add <task> <depends-on>` | Task blocked by another |
| `cw task dep rm <task> <depends-on>` | Remove dependency |
| `cw task dep tree <id>` | Show dependency graph |

### Assignment Commands

| Command | Description |
|---------|-------------|
| `cw task assign <id> <agent>` | Assign task to agent |
| `cw task unassign <id>` | Release task |
| `cw task mine` | List tasks assigned to current agent |

### Output Flags (global)

| Flag | Description |
|------|-------------|
| `--json` | Output as JSON (for agent consumption) |
| `--quiet` | Minimal output (just IDs) |

---

## Agent Workflow

Standard loop for Workers:

```
1. cw task ready --json
2. Pick highest priority task from result
3. cw task update <id> --status in_progress
4. Do the work
5. cw task close <id> --reason "Implemented X"
6. Loop to step 1
```

If `cw task ready` returns empty, the agent's work is done.

---

## Integration Points

### With Initiatives
- Tasks can link to an initiative via `initiative_id`
- When initiative is approved, tasks are generated from its technical concept
- Closing all tasks for an initiative signals initiative completion

### With Orchestrator
- Orchestrator queries `ready_tasks` view to dispatch work
- Assignment tracked to prevent double-dispatch
- Orchestrator can bulk-create tasks from job definitions

### With Workers
- Workers claim tasks via `cw task update --status in_progress`
- Worker ID stored in `assigned_to`
- On worker crash, Supervisor can detect stale assignments and reset

### tRPC Procedures

```typescript
// Suggested tRPC router shape
task.list(filters)      // → Task[]
task.ready(projectId?)  // → Task[]
task.get(id)            // → Task | null
task.create(input)      // → Task
task.update(id, input)  // → Task
task.close(id, reason)  // → Task
task.assign(id, agent)  // → Task
task.history(id)        // → TaskHistory[]
task.depAdd(id, dep)    // → void
task.depRemove(id, dep) // → void
task.depTree(id)        // → DependencyTree
```

---

## Task Granularity Standards

A task must be specific enough for execution without interpretation. Vague tasks cause agents to guess, leading to inconsistent results.

### Quick Reference

| Too Vague | Just Right |
|-----------|------------|
| "Add authentication" | "Add JWT auth with refresh rotation using jose, httpOnly cookie, 15min access / 7day refresh" |
| "Create the API" | "Create POST /api/projects accepting {name, description}, validates name 3-50 chars, returns 201" |
| "Handle errors" | "Wrap API calls in try/catch, return {error: string} on 4xx/5xx, show toast via sonner" |

### Required Task Components

Every task MUST include:

1. **files** — Exact paths modified/created
2. **action** — What to do, what to avoid, WHY
3. **verify** — Command or check to prove completion
4. **done** — Measurable acceptance criteria

See [task-granularity.md](task-granularity.md) for comprehensive examples and anti-patterns.

### Context Budget

Tasks are sized to fit agent context budgets:

| Complexity | Context % | Example |
|------------|-----------|---------|
| Simple | 10-20% | Add form field |
| Medium | 20-35% | Create API endpoint |
| Complex | 35-50% | Implement auth flow |
| Too Large | >50% | **SPLIT REQUIRED** |

See [context-engineering.md](context-engineering.md) for context management rules.

---

## Deviation Handling

When Workers encounter unexpected issues during execution, they follow deviation rules:

| Rule | Action | Permission |
|------|--------|------------|
| Rule 1: Bug fixes | Auto-fix | None needed |
| Rule 2: Missing critical (validation, auth) | Auto-add | None needed |
| Rule 3: Blocking issues (deps, imports) | Auto-fix | None needed |
| Rule 4: Architectural changes | ASK | Required |

See [deviation-rules.md](deviation-rules.md) for detailed guidance.

---

## Execution Artifacts

Task execution produces artifacts:

| Artifact | Purpose |
|----------|---------|
| Commits | Per-task atomic commits |
| SUMMARY.md | Record of what happened |
| STATE.md updates | Position tracking |

See [execution-artifacts.md](execution-artifacts.md) for artifact specifications.

---

## Future Considerations

- **Compaction**: Summarize old closed tasks to reduce DB size (beads does this with LLM)
- **Labels/tags**: Additional categorization beyond type
- **Time tracking**: Estimated vs actual time for capacity planning
- **Recurring tasks**: Templates that spawn new tasks on schedule
