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. 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:| Property | Description |
|---|---|
status | The current state of this task—pending (not started), in_progress (agent is working on it), completed (done) |
content | A human-readable description of what the task involves |
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.

