Agent Todos
Show an agent’s plan as it works. Every step moves from backlog to to do, in progress and done, with live timings, failures and the tool calls behind it. A status pill for above the composer, plan changes you can see, and a review step to edit the plan before it runs.
Coding agents like Claude Code, Codex and Gemini CLI keep a written plan while they work, through tools such as TodoWrite, update_plan and write_todos. Agent Todos turns that plan into one line per step, with the step in progress spelled out (“Running the tests”) and how long each one took.
Every step moves from backlog to to do, in progress, and then done, failed or cancelled. When the agent rewrites its plan, new steps highlight, removed ones collapse out and a short note says what changed. A failed step keeps its reason in view, and long runs of finished steps fold away so the current work stays on screen.
AgentTodosStatus puts the current step and a count in one line above the composer, and AgentTodosReview lets people edit, reorder, add and remove steps before anything runs, then start with ⌘↵. Adapters read each agent’s tool format, including input that is still streaming, and Tool Calls can show the work inside any step.
Add the Pro registry to components.json
components.json Add your token
Create a token on your account page and put it in
.env.localasHEXTAUI_PRO_TOKEN.Add the block
pnpm dlx shadcn@latest add @hextaui-pro/agent-todos
With the AI SDK
getTodosFromParts reads the latest TodoWrite, update_plan or write_todos call in a message, even while its input is still streaming. Show the list in the message and the status pill above the composer.
Review before running
Let people edit, reorder, add and remove steps before the agent starts. Run plan or ⌘↵ hands back the cleaned-up list.
With incremental task tools
For tools that create and update one task at a time, like Claude Code’s TaskCreate and TaskUpdate, fold each call into the list with applyTaskEvent.
Anatomy
The parts you compose, from the outside in.
| Part | Description |
|---|---|
AgentTodos | The full list with its header, progress bar, explanation and plan-change note. |
AgentTodosStatus | A one-line pill with the current step, opening the list in a popover. |
AgentTodosReview | The editable plan shown before the agent starts. |
TodoMark | The status mark on its own, for custom layouts. |
getTodosFromParts, fromTodoWrite, fromUpdatePlan, fromWriteTodos, applyTaskEvent | Adapters from each agent’s tool format to Todo items. |
| Prop | Type | Default |
|---|---|---|
todosSteps in order. | Todo[] | – |
explanationWhy the plan looks the way it does, shown under the progress bar. Codex sends this with update_plan. | string | – |
runningWhether the agent is working. Defaults to true while any step is in progress. | boolean | – |
titleHeader label and region name. | string | "Tasks" |
collapsibleLet the header fold the list away. | boolean | true |
defaultOpenStart open. | boolean | true |
foldAfterFold the finished steps at the top once the list is longer than this. | number | 6 |
| Prop | Type | Default |
|---|---|---|
idStable id. Plan changes are detected by id. | string | – |
contentWhat to do, in the imperative: “Run the tests”. | string | – |
activeFormWhat it’s doing, shown while in progress: “Running the tests”. | string | – |
statusThe stage. pending reads as To do. | "backlog" | "pending" | "in_progress" | "completed" | "failed" | "cancelled" | – |
errorShown under a failed step. | string | – |
durationStored seconds, for history. | number | – |
detailsOpens under the step, usually Tool Calls. | ReactNode | – |
| Prop | Type | Default |
|---|---|---|
todosThe same list. Renders nothing when empty. | Todo[] | – |
runningAnimates the mark and shimmer while true. | boolean | – |
explanationPassed to the list in the popover. | string | – |
| Prop | Type | Default |
|---|---|---|
todosThe proposed plan. | Todo[] | – |
onChangeCalled on every edit. | (todos: Todo[]) => void | – |
onApproveCalled from Run plan or ⌘↵, with empty steps removed and text trimmed. | (todos: Todo[]) => void | – |
onCancelShows Cancel and handles Escape. | () => void | – |
titleHeading. | string | "Review the plan" |
approveLabelButton label. | string | "Run plan" |
getTodosFromParts(parts)
Returns { todos, explanation? } from the newest TodoWrite, update_plan or write_todos call in an AI SDK message, or null.
| Prop | Type | Default |
|---|---|---|
partsWorks on static and dynamic tool parts, including input that is still streaming. | UIMessage["parts"] | – |
applyTaskEvent(todos, event)
Folds one TaskCreate or TaskUpdate call into the list. A status of deleted removes the task.
| Prop | Type | Default |
|---|---|---|
eventThe call, normalised. | { type: "create", id, subject, activeForm? } | { type: "update", id, status?, subject?, activeForm? } | – |
| Key | Action |
|---|---|
| EnterSpace | Opens or folds the list from its header, or a step’s details. |
| ⌘↵ | Runs the plan while it’s being reviewed, unless you’re typing in another field. |
| Enter | In review, adds a step below the current one. |
| ⌫ | In review, removes an empty step and moves to the one above. |
| ⌥↑ | In review, moves the step up. ⌥↓ moves it down. |
| ↑↓ | In review, moves between steps. |
| Esc | Cancels the review when onCancel is set. |
- The list is a labelled region with an ordered list, and each step’s name includes its stage, such as “Running the tests, In progress”.
- A hidden progressbar reports how many steps are done.
- Starting, finishing and failing a step are announced through a polite live region, along with plan changes. Timer ticks are not announced.
- The status pill’s label reads the current step and the count, and it opens the list in a focus-managed popover.
- Review fields are labelled by step number, moves are announced (“Moved to step 2 of 5”), and Enter waits while an input method is composing.
- With reduced motion, the in-progress ring stops spinning, checks appear without drawing, and steps slide into place instantly.
Code
4 files, added to components/blocks/agent-todos.