Progress Card Tool: Durable Session Status for Agents
Learn how the progress_card tool maintains a single durable status card for an agent session, replacing on every write. This page covers usage, adoption nudges, and configuration for developers integrating the tool.
Read this when
- You want an agent to publish durable at-a-glance progress for its current session
- You need the progress_card input, limits, rendering, or clearing contract
progress_card serves as the sole status indicator for an agent within a session. It can hold a sequential action list, a brief Markdown note, or a combination of the two. Since every invocation replaces the entire card, the most recent write determines what anyone tracking the work sees without going through the transcript.
This card represents durable session state. If a connection drops or the page reloads, the latest card is fetched from the Gateway rather than being rebuilt from tool calls or chat history. The transcript only records a short confirmation of the update, not a duplicate of the full card.
Adoption
For non-main sessions, OpenClaw injects a brief progress-card nudge when a web, iOS, Android, or macOS card renderer is linked to the Gateway and the run does not rely on the agent's utility model. Deployments that only use channels, like a WhatsApp-only Gateway, skip this nudge.
The nudge reads:
During multi-step work, keep your progress card current with the progress_card tool; the user follows it instead of reading the transcript.
This nudge does not override tool policy. tools.updatePlan: false or a corresponding tools.deny entry still eliminates progress_card from the run entirely.
Update a card
Neither input field is mandatory:
plan: a maximum of 50 ordered steps. Every step requires non-emptysteptext and astatusset topending,in_progress, orcompleted. Only one step can be markedin_progress.markdown: a concise summary covering what happened, what is stalled, or what is next. Reach for it when a quick note communicates more than the step list; avoid duplicating the plan in Markdown.
As an example:
{
"plan": [
{ "step": "Inspect the failing route", "status": "completed" },
{ "step": "Repair the session owner", "status": "in_progress" },
{ "step": "Run focused verification", "status": "pending" }
],
"markdown": "The failure is isolated to session ownership. No blocker."
}
Each call replaces, not merges. Leaving out markdown deletes the prior note; leaving out plan deletes the prior checklist.
The tool responds with a brief confirmation like Progress card updated (rev 4, 1/3 done) or Progress card updated (rev 4) when no plan exists. Its structured output includes the revision and either completed/total step counts or null when a plan is absent. OpenClaw also fires plan events for native apps and channel renderers during their migration, but the durable card remains the authoritative source.
Format the note
Pick the format that makes the current state quickest to scan: a table suits comparisons or metrics, a progress bar fits a single long operation, and a checklist works only for genuinely ordered tasks. Drop the checklist when a table, bar, or sentence conveys it better, and avoid repeating the same details across both the plan and Markdown. Markdown supports standard formatting, links, and optional progress bars:
Tests are running.
<progress value="3" max="7"></progress>
| check | state |
| ---------- | ------- |
| unit tests | passed |
| live flow | running |
The Control UI renders progress elements using value and max attributes. Any other raw HTML gets removed by the Markdown sanitizer.
Limits
- Markdown: capped at 8,192 UTF-8 bytes.
- Plan: capped at 50 steps.
- Step text: non-empty and capped at 512 UTF-8 bytes per step.
- Active work: no more than one
in_progressstep.
Before storing the card, the Gateway strips invisible Unicode and bidirectional control characters from Markdown and step text.
Clear a card
Invoke progress_card with both parts missing or empty to delete the current card:
{}
An empty plan paired with empty or whitespace-only Markdown also removes it. A successful clear returns Progress card cleared.
Where the card appears
The active chat displays exactly one live card:
- With the session rail visible, the card sits in the rail.
- At narrow widths hiding the rail, the card appears in the collapsible surface next to the composer.
These two placements never coexist. Hovering over a session row in the sidebar or a session-reference link in chat shows the same card for that session. Every placement reads the identical Gateway-backed state and updates after progressCard.changed notifications.
Pin the card to the dashboard
Apply the dashboard tool to keep the live card on the current session's dashboard:
{
"action": "widget_put",
"name": "session-progress",
"title": "Session progress",
"pluginKind": "session:progress",
"size": "md"
}
Drop props.sessionKey to follow the dashboard's session. To display another session's card, include "props": { "sessionKey": "agent:main:release" }. The active connection must be part of that session; otherwise, pick an accessible session or adjust its sharing.