> ## Documentation Index
> Fetch the complete documentation index at: https://haico.gr/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Plan (todo) tools

> Agent tools for the plan: the agent's own execution ledger of nested, ordered todo steps.

The `TodoTools` collection manages the **plan** (the Planning panel in the UI): the agent's own execution ledger of what it has done and what remains. One instance is created per thread, bound to its `thread_id`, so every tool targets the right conversation without `thread_id` being an LLM-facing parameter.

The plan is an arbitrarily-nested, depth-first (pre-order) tree. Every step is addressed by a **stable 1-based flat index** (its position in the pre-order list, exactly what [`list_todos`](#list_todos) prints). The dotted outline numbers (`1`, `1.1`, `1.1.1`, `2`) are display-only; the tools always take the flat index. Every mutating tool is **batch-shaped**: it takes a list so the agent can act on many steps in one call (pass a one-element list to act on a single step). There are deliberately no singular variants.

Shared conventions (the `@workspace_tool` contract, the `{success, summary}` JSON envelope, and the injected `action_and_reasoning` argument) are documented in [Tools](/docs/tools). Every tool below also receives the injected `action_and_reasoning` argument described there; it is not listed as an argument row.

Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py)

## `add_todos`

Add one or more steps to the plan as a nested outline, either appended at the end or nested under an existing step.

**Description shown to the agent:**

> Add todo steps to the plan in one call, passed as a nested outline (each step has `text` and a `depth`). Pass `parent_index` to nest the whole outline as sub-steps under an existing todo step; omit it to append at the end as top-level steps. Use this for every add, pass a one-element list to add a single step.

**Arguments**

| Argument       | Type                                | Required            | Description shown to the agent                                                                                                                                                                |
| -------------- | ----------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `steps`        | `array` of `{text, depth}`          | Yes                 | The todo steps to add, as an ordered outline (depth-first). Each step has `text` and a `depth` (nesting level). Pass a single step as a one-element list.                                     |
| `parent_index` | `integer \| null` (1-based, `>= 1`) | No (default `null`) | 1-based index (as shown by `list_todos` / the plan block) of an existing todo step to nest the whole outline under. Omit to append the outline at the end of the plan as new top-level steps. |

Each item in `steps` is a `PlanStep` object:

| Field   | Type                            | Required | Description shown to the agent                                                                                                                     |
| ------- | ------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`  | `string`                        | Yes      | Concise description of one todo step.                                                                                                              |
| `depth` | `integer` (`>= 0`, default `0`) | No       | Nesting level within the outline: 0 = top-level todo step, 1 = sub-step, 2 = sub-sub-step, and so on. Depth may only increase one level at a time. |

**Returns:** a confirmation string with the number of steps added, e.g. `added 3 todo steps`. This becomes the `summary` of the success envelope.

**Implementation:** maps each `PlanStep` to `{text, depth}` and calls `WorkspaceRepository.add_todos_bulk(thread_id, items, parent_index=...)`, which inserts the outline into the pre-order tree at the chosen position. Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py).

## `toggle_todos`

Flip one or more steps between done and not-done.

**Description shown to the agent:**

> Toggle one or more todo steps done / not-done by their 1-based indices (pass a list; a single step is a one-element list).

**Arguments**

| Argument  | Type                           | Required | Description shown to the agent                                                                               |
| --------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------ |
| `indices` | `array` of `integer` (1-based) | Yes      | 1-based positions of the todo steps to flip done / not-done (as shown by `list_todos`). Pass one or several. |

**Returns:** a summary of the resulting statuses, e.g. `toggled 2 todo steps: #1 now done, #2 now pending`, or `no matching todo steps found` when no index is in range.

**Implementation:** reads the current plan, resolves each in-range index to its row id **up front** (so the indices reference the plan as it stood at call time), then calls `repo.toggle_todo(todo_id)` per target. Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py).

## `update_todos`

Rewrite the text of one or more existing steps, keeping their position, depth, and done status.

**Description shown to the agent:**

> Rewrite the text of one or more existing todo steps. Pass a list of `{index, text}`; a single edit is a one-element list.

**Arguments**

| Argument  | Type                       | Required | Description shown to the agent                                                                |
| --------- | -------------------------- | -------- | --------------------------------------------------------------------------------------------- |
| `updates` | `array` of `{index, text}` | Yes      | The todo steps to rewrite, each as `{index, text}`. Pass a single edit as a one-element list. |

Each item in `updates` is a `TodoTextUpdate` object:

| Field   | Type                        | Required | Description shown to the agent                                           |
| ------- | --------------------------- | -------- | ------------------------------------------------------------------------ |
| `index` | `integer` (1-based, `>= 1`) | Yes      | 1-based position of the todo step to rewrite (as shown by `list_todos`). |
| `text`  | `string`                    | Yes      | New text for the todo step.                                              |

**Returns:** a confirmation string with the number of steps updated, e.g. `updated 2 todo steps`, or `no matching todo steps found` when no index is in range.

**Implementation:** resolves indices against the plan at call time (before any edit, so they do not shift as steps are rewritten), then calls `repo.update_todo_text(todo_id, text)` per target. Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py).

## `remove_todos`

Delete one or more steps; removing a parent step also removes all of its sub-steps.

**Description shown to the agent:**

> Delete one or more todo steps by their 1-based indices (pass a list; a single step is a one-element list). NOTE: removing a parent todo step also removes ALL of its sub-steps. Use when the plan changes and todo steps no longer apply.

**Arguments**

| Argument  | Type                           | Required | Description shown to the agent                                                                                                                                      |
| --------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `indices` | `array` of `integer` (1-based) | Yes      | 1-based positions of the todo steps to delete (as shown by `list_todos`). Pass one or several. NOTE: removing a parent todo step also removes ALL of its sub-steps. |

**Returns:** a confirmation string with the total number of steps removed, e.g. `removed 4 todo steps`, or `no matching todo steps found` when no index is in range.

**Implementation:** resolves all target row ids up front, then calls `repo.remove_todo_subtree(thread_id, todo_id)` per target, which cascades to the step's descendants. Because removal cascades, an index that named a sub-step already taken out by its parent is simply skipped. Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py).

## `list_todos`

Read the current plan with its numbers, nesting, and statuses. Rarely needed, since the plan is injected into the agent's context every turn.

**Description shown to the agent:**

> List the current plan with numbers, nesting, and statuses.

**Arguments**

None (the agent still passes the injected `action_and_reasoning`).

**Returns:** newline-separated lines of the form `#N  D.D  [x] text`, where `N` is the 1-based flat index that every todo tool expects and `D.D` is the dotted outline number reflecting nesting (`[x]` marks done, `[ ]` pending), or `(no todo steps yet)` when the plan is empty.

**Implementation:** reads `repo.list_todos(thread_id)` and renders each row through `compute_dotted_numbers` (in [`_planning_format.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/_planning_format.py)) to produce the dotted outline numbers. Source: [`backend/app/tools/todos.py`](https://github.com/petrosrapto/HAICO/blob/main/backend/app/tools/todos.py).
