AGENTS.md@packages/coding-agent/src/core/extensions/builtin/todotools · git:20260924.3a80281 · 2026-09-24 · sha256 b53245ba43055c3a
AGENTS.md@packages/coding-agent/src/core/extensions/builtin/todotools git:20260924.3a80281A
Immutable. This exact content never changes and is served at /api/v1/blob/b53245ba43055c3a.
# builtin/todotools
Builtin extension #8 (id `todowrite`). The op-based phased **todo** tool ported from
oh-my-pi, plus the `/todo` command suite and the `todo-sidebar` widget. Fully diverged from
`../pi-extensions/pi-todotools`; `changes.md` is the fork tracker.
## FILES (by cluster)
- **Entry/registration**: `index.ts` (in-memory `currentState = { phases, ask }`, session
resync, Cursor native-todo mirror, `Task_Management` system-prompt section),
`tools/todo.ts` (schema, `execute`, renderers), `commands.ts` (`/todo` verbs).
- **State**: `todo-types.ts`, `todo-storage.ts` (branch readers, parsers, type guards),
`todo-operations.ts`, `todo-query.ts`, `todo-resolution.ts`, `fuzzy-match.ts`,
`normalize.ts` (malformed-call auto-correction), `todo-ask.ts` (Ask capture);
`state.ts` is the re-export barrel other builtins import.
- **Format/prompt**: `todo-format.ts` (`formatSummary`, `describeAskNowNext`),
`prompt.ts` (`TODO_TOOL_DESCRIPTION`, `TASK_MANAGEMENT_SECTION`), `markdown.ts`.
- **UI**: `todo-widget.ts` (10-line window model), `todo-widget-component.ts`
(completion strike animation), `native-todo-mirror.ts`.
## ASK / NOW / NEXT
Every todo result (success and thrown error) opens with `Ask:`, `Now:`, `Next:` lines and a
blank line before the list summary. The Ask is captured mechanically, never from a model
parameter: a list-creating call (`init`, or `append` into an empty list) anchors to the
branch's first user message when no `senpi.todo-state` entry exists yet, otherwise to the
newest user message (a mid-task `init` is an explicit redirect). Ask-user answer frames are
skipped. `start` / `done` / `drop` / `rm` / `append` keep the anchor. A compaction restore
request (`compaction.todo-restore-request`) newer than the last list and the last user
message re-emits its snapshot's ask. Now is `nextActionableTask`; Next is the first pending
task in phase order that is not Now.
## CONVENTIONS
- **Persistence**: `senpi.todo-state` custom entries, schema `v2`, carrying `phases` and the
optional `ask`; the latest entry on the branch wins (`getLatestTodoStateFromBranchEntries`).
Every writer (tool, `/todo`, native mirror) carries the current ask forward.
- **Tool errors are THROWN, never returned** (the agent loop ignores a returned `isError`).
The thrown message keeps the header and the full remaining-items echo.
- **Tasks are content-keyed**; no generated ids. Keep `details.op` / `details.phases`
stable - `goal/todo-gate.ts` and `compaction/todo-bridge.ts` read them.
- The widget stays within its 10-line budget; the Ask line renders only in the tool result
and the `/todo` view.
## TESTS
`test/suite/todo-*.test.ts` (faux harness from `test/suite/harness.ts` or a captured
`registerTodoTool` / `registerTodoCommand` with a fake `pi`), `todo-ask-now-next.test.ts`
for the Ask/Now/Next contract, `test/compaction/todo-*.test.ts` for the snapshot bridge,
and the golden `test/suite/fixtures/task-management-section.txt`. No real providers.