pi-todo-agent
Pi extension. A todo list the model manages through a `todo` tool, rendered as a live overlay above the editor. Zero runtime dependencies.
Package details
Install pi-todo-agent from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-todo-agent- Package
pi-todo-agent- Version
0.3.0- Published
- Sep 17, 2026
- Downloads
- 278/mo · 278/wk
- Author
- derangga
- License
- MIT
- Types
- extension
- Size
- 67.3 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-todo-agent
Pi extension. A todo list the model manages through a todo tool, rendered as a live overlay above the editor until it's done, then handed off to the chat as a struck-through record. Zero runtime dependencies.
The model plans multi-step work as tasks, marks each one in progress and completed as it works, and you watch the list update in real time. State survives compaction and reloads, and every session gets its own list.
Install
pi install pi-todo-agent
The package declares no dependencies. It needs three host-provided peers, which any Pi install already ships: @earendil-works/pi-coding-agent, @earendil-works/pi-tui, and typebox.
The todo tool
todo({ action: "create", subject: "Research existing tool", blockedBy: [] })
todo({ action: "update", id: 1, status: "in_progress", activeForm: "researching" })
todo({ action: "list" })
todo({ action: "get", id: 1 })
todo({ action: "delete", id: 1 })
todo({ action: "clear" })
Statuses are a 4-state machine: pending → in_progress → completed, plus deleted as a tombstone. Completed tasks never reopen; clear resets the list and the id counter.
| Action | Required params | Notes |
|---|---|---|
create |
subject |
Adds a task in pending. Optional description, activeForm, blockedBy. |
update |
id + one mutable field |
Changes status, subject, description, activeForm, or the dependency set. |
list |
— | All tasks; filter by status, pass includeDeleted to see tombstones. |
get |
id |
One task with its blockedBy and reverse blocks edges. |
delete |
id |
Tombstones the task; the id is never reused. |
clear |
— | Drops every task and resets ids to 1. |
Dependencies: blockedBy holds ids a task waits on. Rejected calls leave the list untouched: unknown ids, already-deleted ids, self-blocks, and dependency cycles are all validated before the state changes. update merges addBlockedBy/removeBlockedBy additively.
Invalid transitions are rejected with the list unchanged, and an update that changes nothing reports "No change" so the model does not re-issue it in a loop.
When a mutation completes the last visible task, the tool result reports a one-line signal ("All N tasks done.") — the full list is no longer repeated here; see the transcript entry below.
The overlay
A Todos (2/5) widget renders above the editor while any task is visible. It caps at 12 content rows, dropping completed rows first and summarizing the rest as +N more. When Pi's tool output is expanded, every row shows. Completed rows fade out when the next turn starts, and the widget hides itself entirely when the list is empty. Expanding the list again is as simple as creating another task.
The instant every visible task is completed, the overlay stops rendering the list altogether — it hands off to the transcript entry below rather than sitting above the editor with nothing left to track.
The completed-list entry
Once the last visible task completes, the full list is appended to the chat as a plain scrollback block, completed subjects struck through, right under the todo call that finished it. It's display-only: a custom session entry, not a message, so it never enters the model's context and never costs a token on later turns. It survives /reload and compaction like the rest of the conversation. Starting a new list (adding another task) mounts a fresh overlay and, on its own completion, appends its own block below — each finished list gets one entry, once.
Sessions
State is partitioned by session id. Detached or child sessions get their own list instead of clobbering yours. On session_start, session_compact, and session_tree, the extension replays the latest todo snapshot from the conversation branch, so the list survives compaction and /reload. On shutdown the session's slot is evicted.
Configuration
None. The prompt guidance and the overlay row budget are hardcoded constants in the source. This is a deliberate trade for keeping the package at zero dependencies.
Not compatible with @juicesharp/rpiv-todo
Both packages register a tool named todo. Install one or the other, not both.
License
MIT