Tracks the steps of the current task and their status. The list is already populated when the task starts — the planner fills the todo with the plan's steps — so you normally never call set; you call update as you go and view when you lose the thread.
The tool is the record of what you actually verified. Marking a step done without a validation field is rejected outright, which is the point: it stops "done" from meaning "I moved on".
Tasks are per-session and do not survive a server restart.
| Parameter | Required | Description | ||||
|---|---|---|---|---|---|---|
op |
yes | set \ |
view \ |
update \ |
add \ |
clear. |
tasks |
for set/add |
Ordered list of step descriptions (strings). | ||||
index |
for update |
1-based step number. | ||||
status |
for update |
pending \ |
in_progress \ |
done \ |
failed \ |
skipped. |
validation |
for status: "done" |
How you verified the result. |
An omitted op is inferred from the arguments you did send — {"index": 1, "status": "in_progress"} is read as an update, {"tasks": [...]} as a set — so a missing discriminator costs you nothing. An explicitly wrong op is rejected with the list of valid ones. A status outside the five is stored as sent rather than rejected, which means a typo ("Done") silently stops the step from ever counting as done — spell them lower-case exactly as listed.
update — the one you use constantly{"op": "update", "index": 1, "status": "in_progress"}
{"op": "update", "index": 1, "status": "done", "validation": "ran uv run pytest tests/unit/tools -q — 38 passed"}
{"op": "update", "index": 2, "status": "failed", "validation": "ssh timeout after 60s; host unreachable, tried both key and password"}
index is 1-based and must be within the plan — an out-of-range index returns the plan's length so you can correct it.done requires validation. Without it the call fails with validation_required and nothing changes. Say what you checked, not what you did: "ran X — output matched Y", "read the file and confirmed the block is gone".failed without validation is accepted, with a tip. Provide one anyway — it is what makes re-planning possible.in_progress when you start a step, and move it to done/failed before starting the next one. A status that lags reality turns the todo into decoration.viewRe-orients you: current statuses plus the validation notes. Call it after a sub-agent returns, after a long tool chain, or whenever the plan in your head may have drifted from the plan in the store. "No plan set for this session." means exactly that — no plan exists yet.
setCreates or replaces the Master Plan. Use it only when the plan must be rebuilt mid-task. It takes the whole list and discards every existing status, so it is the expensive, destructive option.
addAppends steps discovered mid-task and preserves existing steps and their statuses. This is what you want for a newly surfaced subtask — never rebuild the list with set to add one line. Requires a plan to already exist.
clearResets the plan. Rarely right: a finished plan is the record of what was verified, and the final answer should be able to point at every step marked done.
{"op": "update", "index": N, "status": "in_progress"}.{"op": "update", "index": N, "status": "done", "validation": "..."}.in_progress when you answer.Before your final message, every completed step — including the last one — must be done with validation. If you discover work the plan does not cover, add it rather than silently doing it.
set instead of add, wiping the statuses of steps already finished.done at the end in one sweep, with validations written from memory. Verify per step; the todo is only worth reading if it tracked reality while it happened.in_progress in the final answer.view as optional after a sub-agent run — its steps are not in your head.