Files
openclaw/docs/tools/progress-card.md
Peter Steinberger 5b5fdacfda feat(ui): dock the session progress card beside a wide composer (#129141)
* feat(ui): dock the session progress card beside a wide composer

The progress card had two placements: the companion rail when that side
panel is open, otherwise a collapsed one-line bar stacked inside the
composer box. On a wide chat the composer stays centered at the
transcript width, so the space either side of it sits empty while the
card is squeezed into the composer.

Add a third placement. When the measured free gutter beside the composer
is at least 280px, the card docks into it with its full checklist
expanded; below that it falls back to the existing composer bar, and an
open companion rail still wins. Exactly one placement renders at a time,
now expressed as a closed {card, placement} prop so the composer bar and
the dock cannot both draw the same card.

The gutter is measured from the DOM by a small ResizeObserver controller
rather than derived from the pane width: the transcript width is a
browser-local setting in arbitrary CSS units, and an open side panel
shrinks the conversation column without changing the pane. The dock is
positioned absolutely in that gutter, so the transcript and composer
never shift when a card appears or is dismissed, and its inline-start
edge repeats the composer's own half-width formula through a shared
--chat-composer-side-inset token so the two stay in agreement.

* fix(ui): keep the new-session composer sized outside the chat surface

The composer shell tokens are declared on .chat, but the new-session page
reuses .agent-chat__composer-shell outside it. There the var() had no
value, so the whole width declaration was invalid and dropped, and the
composer stretched full-width instead of holding its 48rem centered box.

Give both tokens their literal fallback at the use site, matching the
neighbouring --chat-thread-max-width. The custodian surface was already
immune because it overrides width outright.

Caught by ui/src/e2e/new-session-page.places.e2e.test.ts, which is the
regression test for this: it failed on the previous head and passes now.
2026-08-25 01:34:09 -07:00

109 lines
5.1 KiB
Markdown

---
summary: "Maintain one durable plan and status card for a session"
title: "Progress card"
sidebarTitle: "Progress card"
read_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` is the single agent status tool for a session. It stores an ordered step plan, a compact Markdown note, or both. Each call replaces the whole card, so the latest write is the source of truth for someone following the work without reading the transcript.
The card is durable session state. A reconnect or page reload reads the latest card from the Gateway instead of reconstructing it from tool events or transcript history. The transcript keeps only a short update receipt, not another full copy of the card.
## Adoption
OpenClaw adds a short progress-card reminder only for non-main sessions when a web, iOS, Android, or macOS card renderer is paired with the Gateway and the run is not using the agent's utility model. Channel-only deployments such as a WhatsApp-only Gateway do not receive the reminder.
The reminder says:
> During multi-step work, keep your progress card current with the progress_card tool; the user follows it instead of reading the transcript.
The reminder does not override tool policy. `tools.updatePlan: false` or a matching `tools.deny` entry still removes `progress_card` from the run entirely.
## Update a card
Both input fields are optional:
- `plan`: up to 50 ordered steps. Each step has non-empty `step` text and a `status` of `pending`, `in_progress`, or `completed`. At most one step may be `in_progress`.
- `markdown`: a compact narrative about what happened, what is blocked, or what comes next. Use it when a glanceable note says more than the step list; do not repeat the plan in Markdown.
For example:
```json
{
"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."
}
```
Every call is a replacement, not a patch. Omitting `markdown` removes the previous note; omitting `plan` removes the previous checklist.
The tool returns a short receipt such as `Progress card updated (rev 4, 1/3 done)` or `Progress card updated (rev 4)` when there is no plan. Its structured result contains the revision and either completed/total step counts or `null` when no plan is present. OpenClaw also emits plan events for native apps and channel renderers during their migration, but the durable card remains the authoritative state.
## Format the note
Choose the representation that makes the current state easiest to scan: use a table for comparisons or metrics, a progress bar for one long operation, and a checklist only when the work is genuinely sequential. Omit the checklist when a table, bar, or sentence says it better, and do not repeat the same facts across the plan and Markdown. Markdown accepts ordinary formatting, links, and optional progress bars:
```md
Tests are running.
<progress value="3" max="7"></progress>
| check | state |
| ---------- | ------- |
| unit tests | passed |
| live flow | running |
```
The Control UI renders `progress` elements with `value` and `max` attributes. Other raw HTML is stripped by the Markdown sanitizer.
## Limits
- Markdown: at most 8,192 UTF-8 bytes.
- Plan: at most 50 steps.
- Step text: non-empty and at most 512 UTF-8 bytes per step.
- Active work: at most one `in_progress` step.
The Gateway removes invisible Unicode and bidirectional control characters from Markdown and step text before storing the card.
## Clear a card
Call `progress_card` with both parts absent or empty to remove the current card:
```json
{}
```
An empty plan plus empty or whitespace-only Markdown also clears it. A successful clear returns `Progress card cleared`.
## Where the card appears
The current chat shows exactly one live card:
- When the session rail is visible, the card appears in the rail.
- Otherwise, when the chat is wide enough that the centered composer leaves a free gutter, the card docks in that space beside the composer with its full checklist expanded.
- At narrower widths the card appears in the collapsible surface inside the composer.
The placements are mutually exclusive. Hover a session row in the sidebar or a session-reference link in chat to see the same card for that session. All card placements read the same Gateway-backed state and refresh after `progressCard.changed` notifications.
## Pin the card to the dashboard
Use the `dashboard` tool to keep the live card on the current session's dashboard:
```json
{
"action": "widget_put",
"name": "session-progress",
"title": "Session progress",
"pluginKind": "session:progress",
"size": "md"
}
```
Omit `props.sessionKey` to follow the dashboard's session. To show another session's card, add `"props": { "sessionKey": "agent:main:release" }`. The current connection must participate in that session; otherwise select an accessible session or change its sharing.