`GET /api/tasks/{id}/subtasks` — list the delegated child tasks of a parent task. Workspace-scoped: a parent task in another workspace is `NotFound`.
const url = 'https://example.com/api/tasks/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/subtasks';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/tasks/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/subtasksParameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Parent task ID
Responses
Section titled “Responses”object
Agent cost (USD) + token usage, folded in by the tasks-board handler from
task_outcomes. None for a task with no recorded outcome and on
endpoints that don’t join usage (From<Task> defaults them).
Task lifecycle status — an OPEN String, not a closed enum. The tasks.status
column has no DB CHECK; its PRIMARY lifecycle is pending on create →
starting/running → terminal completed/failed/cancelled. The wire type
stays an unconstrained string on purpose: a value outside that set (a demo/seed
state, or a future status) must render gracefully, never break the whole board.
A closed-enum narrowing here made ONE unmodelled row fail the client contract
validation and blank the entire Tasks list (ADR 0047 fail-loud is right for
structural drift, wrong for an open evolving lexeme). The client maps known
values to a tone/label + falls back to neutral for the rest.
#538 — the (server-truncated) outcome summary, folded in by the tasks-board
handler from task_outcomes; drives the per-task TL;DR. None for a task
with no recorded summary and on endpoints that don’t join usage.
Example
[ { "status": "running" }]