todos array
directly from the agent’s state, rendering each item with its current status as
the agent works through its plan. It’s a progress dashboard built on the same
useStream hook you use for chat — demonstrating that agent state can power any
UI, not just message bubbles.
How it works
In a LangGraph agent, state isn’t limited to messages. You can define custom state keys that hold arbitrary data — in this case, atodos array. As the
agent executes its plan, it updates each todo’s status from "pending" to
"in_progress" to "completed". The useStream hook exposes these custom
state values via stream.values, and your UI renders them reactively.
The flow looks like this:
- User submits a request
- Agent creates a plan and populates
todosin its state - Agent begins executing — each todo transitions through
pending→in_progress→completed stream.values.todosupdates in real time as the agent progresses- Your UI re-renders the todo list with current statuses
Setting up useStream
No special configuration is needed — just pointuseStream at your agent and
read the todos from stream.values.
Define a TypeScript interface matching your agent’s state schema and pass it as a type parameter to useStream for type-safe access to state values, including custom state keys like todos. In the examples below, replace typeof myAgent with your interface name:
The Todo interface
Each todo in the array has a simple structure:
The agent populates this array when it creates its plan, then updates individual
items as it executes each step.
Building the TodoList component
The todo list renders each item with a status icon, color coding, and visual styling that reflects the current state:Progress bar
A visual progress bar gives users an at-a-glance summary of overall completion:Individual todo items
Each item gets a status icon, color-coded text, and strikethrough styling for completed tasks:in_progress icon uses animate-pulse to draw attention to the currently
active task.
Calculating progress
Derive progress metrics directly from the todos array:Combining with chat messages
The todo list works alongside the regular chat interface. A practical layout shows the todo list as a persistent sidebar or header panel, with chat messages below:Custom state beyond todos
This pattern demonstrates a powerful principle:stream.values can expose
any custom state your agent defines, not just messages. The todos array is
just one example. You could use the same approach for:
- Progress metrics —
stream.values.progresswith numeric completion data - Generated artifacts —
stream.values.documentwith a structured document the agent is building - Decision logs —
stream.values.decisionstracking every choice the agent made - Resource lists —
stream.values.sourceswith links and references the agent found
Custom state keys are defined in your LangGraph graph’s state schema. The
useStream hook automatically includes them in stream.values — no additional
client-side configuration is needed.Animating transitions
Todo status transitions happen in real time, and smooth animations make these changes feel polished rather than jarring:transition-all duration-300 classes ensure that color changes,
strikethrough, and opacity shifts all animate smoothly.
Use cases
The todo list pattern fits any scenario where an agent executes a structured plan:- Project planning — agent breaks a project into tasks and works through them sequentially
- Research workflows — each research question becomes a todo that the agent investigates and completes
- Data processing — steps like ingestion, validation, transformation, and export each get their own todo
- Onboarding flows — agent walks through setup steps, checking off each one as it configures services
- Report generation — sections of a report become todos: gather data, analyze trends, write summary, format output
Handling empty and loading states
Handle the initial state before the agent has created its plan:Best practices
- Show the todo list prominently — it’s the primary progress indicator for plan-based agents. Don’t bury it below the fold.
- Animate status transitions — smooth transitions make the agent feel more responsive. Use CSS transitions on background color, text decoration, and opacity.
- Only highlight one
in_progressitem — agents typically work on one task at a time. If multiple items show asin_progress, the UI gets noisy. Consider only pulsing the first one. - Collapse or dim completed items — as the list grows, completed items become less relevant. Reduce their visual weight so users focus on what’s still happening.
- Show the progress percentage — a single number like “67% complete” is immediately understandable, even from across the room.
- Keep the todo list in sync — because
stream.valuesupdates reactively, the todo list stays current automatically. Don’t add manual polling or refresh logic.
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

