Files
openclaw-openclaw/docs/concepts/progress-drafts.md
Peter Steinberger f7d7148cf0 docs: rewrite published docs grounded in current source (#100142)
Source-grounded rewrite of 529 published docs pages with per-unit information-loss verification: 1,713 factual corrections cited to src/**, generated surfaces regenerated, frontmatter titles preserved for i18n, release notes pages untouched. All docs gates green.

Closes #100141
2026-07-05 00:32:47 -04:00

14 KiB

summary, read_when, title
summary read_when title
Progress drafts: one visible work-in-progress message that updates while an agent runs
Configuring visible progress updates for long-running chat turns
Choosing between partial, block, and progress streaming modes
Explaining how OpenClaw updates one channel message while work is in progress
Troubleshooting progress drafts, standalone progress messages, or finalization fallback
Progress drafts

Progress drafts turn one channel message into a live status line while an agent works, instead of a stack of temporary "still working" replies. Set channels.<channel>.streaming.mode: "progress" and OpenClaw creates the message once real work starts, edits it as the agent reads, plans, calls tools, or waits for approval, then turns it into the final answer.

Shelling...
📖 from docs/concepts/progress-drafts.md
🔎 Web Search: for "discord edit message"
🛠️ Bash: run tests
Discord already defaults to `streaming.mode: "progress"` when `channels.discord.streaming.mode`/`streamMode` are unset, so progress drafts show up there without any config. Every other channel defaults to `partial` or `off`; see [Streaming and chunking](/concepts/streaming#channel-mapping) for the full per-channel default table.

Quick start

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
      },
    },
  },
}

Defaults from here: an automatic one-word label, a start delay of 5 seconds (or immediately on a second work event), compact progress lines while useful work happens, and suppression of the older standalone progress messages for that turn.

This page covers the progress-draft experience and its config knobs. For the full streaming-mode matrix, per-channel runtime notes, and legacy key migration, see Streaming and chunking.

What users see

Part Purpose
Label Short starter/status line such as Working or Shelling.
Progress lines Compact run updates using the same tool icons and detail formatter as /verbose.

The label appears once the agent starts meaningful work and stays busy for the initial delay, or a second work event fires immediately. It sits at the top of the rolling progress-line list, so it scrolls away once enough concrete work lines appear. Plain text-only replies never show a progress draft; a line appears only for real work updates, for example 🛠️ Bash: run tests, 🔎 Web Search: for "discord edit message", or ✍️ Write: to /tmp/file.

The final answer replaces the draft in place when the channel can safely do that; otherwise OpenClaw sends the final answer through normal delivery and cleans up or stops updating the draft (see Finalization).

Choose a mode

channels.<channel>.streaming.mode controls the visible in-progress behavior:

Mode Best for What appears in chat
off Quiet channels Only the final answer.
partial Watching answer text appear One draft edited with the latest answer text.
block Larger answer-preview chunks One preview updated or appended in bigger chunks.
progress Tool-heavy or long-running turns One status draft, then the final answer.

Pick progress when users care more about "what is happening" than watching answer text stream token by token; partial when the answer text itself is the progress signal; block for larger preview chunks. On Discord and Telegram, streaming.mode: "block" is still preview streaming, not normal block-reply delivery — use streaming.block.enabled (or legacy blockStreaming) for that.

Configure labels

Progress labels live under channels.<channel>.streaming.progress. The default label is "auto", which picks from OpenClaw's built-in single-word label pool:

Working, Shelling, Scuttling, Clawing, Pinching, Molting, Bubbling, Tiding,
Reefing, Cracking, Sifting, Brining, Nautiling, Krilling, Barnacling,
Lobstering, Tidepooling, Pearling, Snapping, Surfacing

Use a fixed label:

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          label: "Investigating",
        },
      },
    },
  },
}

Use your own label pool (still picked at random/by seed when label: "auto"):

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          label: "auto",
          labels: ["Checking", "Reading", "Testing", "Finishing"],
        },
      },
    },
  },
}

Hide the label and show only progress lines:

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          label: false,
        },
      },
    },
  },
}

Control progress lines

Progress lines come from real run events: tool starts, item updates, task plans, approvals, command output, patch summaries, and similar agent activity. They are enabled by default (progress.toolProgress, default true).

Tools can also emit typed progress while a single call is still running. That is how a slow fetch or search updates the visible draft before the tool returns its final result. The progress update is a partial tool result with empty model content and explicit public channel metadata:

{
  "content": [],
  "progress": {
    "text": "Fetching page content...",
    "visibility": "channel",
    "privacy": "public",
    "id": "web_fetch:fetching"
  }
}

OpenClaw renders only progress.text in the channel progress UI. The normal tool result still arrives later as content/details and is the only part returned to the model.

When adding progress to a tool, emit a short, generic message and delay it until the operation has been pending long enough to be useful. web_fetch does exactly this with a 5-second delay:

const clearProgressTimer = scheduleToolProgress(
  onUpdate,
  { text: "Fetching page content...", id: "web_fetch:fetching" },
  5_000,
  { signal },
);

try {
  return await runToolWork();
} finally {
  clearProgressTimer();
}

Fast calls show no progress line; long calls show one while still pending; canceled calls clear the timer before stale progress can appear. Progress text is a public UI side channel, so it must never include secrets, raw arguments, fetched content, command output, or page text.

Detail mode

OpenClaw uses the same formatter for progress drafts and /verbose:

{
  agents: {
    defaults: {
      toolProgressDetail: "explain", // explain | raw
    },
  },
}

"explain" is the default and keeps drafts stable with concise labels. "raw" appends the underlying command when available, which is useful while debugging but noisier in chat. For example, a node --check /tmp/app.js call renders differently by mode:

Mode Progress line
explain 🛠️ check js syntax for /tmp/app.js
raw 🛠️ check js syntax for /tmp/app.js · node --check /tmp/app.js

Command/exec text

streaming.progress.commandText (default "raw") controls how much command detail shows next to exec/bash progress lines, independent of the detail mode above. Set it to "status" to keep a tool-progress line visible while hiding the command text entirely:

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          commandText: "status",
        },
      },
    },
  },
}

Commentary lane

streaming.progress.commentary (default false) interleaves the model's pre-tool commentary/preamble narration (💬, for example "I'll check... then ...") with tool lines in the draft. See Streaming and chunking for the shared config shape across channels.

Line limits

Limit how many lines stay visible (default 8):

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          maxLines: 4,
        },
      },
    },
  },
}

Progress lines are compacted automatically to reduce chat-bubble reflow while the draft is edited, and OpenClaw truncates long lines so repeated draft edits do not wrap differently on every update. The default per-line budget is 120 characters; prose cuts at a word boundary, while long details such as paths or raw commands are shortened with a middle ellipsis so the suffix stays visible.

Tune the per-line budget:

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          maxLineChars: 160,
        },
      },
    },
  },
}

Rich rendering (Slack)

Slack can render progress lines as structured Block Kit fields instead of plain text:

{
  channels: {
    slack: {
      streaming: {
        mode: "progress",
        progress: {
          render: "rich",
        },
      },
    },
  },
}

Rich rendering always sends the same plain-text body alongside the Block Kit fields, so clients that cannot render the richer shape still show the compact progress text.

Hide tool/task lines

Keep the single progress draft but hide tool and task lines:

{
  channels: {
    discord: {
      streaming: {
        mode: "progress",
        progress: {
          toolProgress: false,
        },
      },
    },
  },
}

With toolProgress: false, OpenClaw still suppresses the older standalone tool-progress messages for that turn — the channel stays visually quiet until the final answer, except for the label if one is configured.

Channel behavior

Channel Progress transport Notes
Discord Send one message, then edit it. Defaults to progress mode; final text edits in place when it fits one safe preview message.
Matrix Send one event, then edit it. Account-level streaming config controls account-level drafts.
Microsoft Teams Native Teams stream in personal chats. streaming.mode: "block" maps to Teams block delivery instead.
Slack Native stream or editable draft post. Needs a reply thread target; top-level DMs without one still get draft preview posts and edits.
Telegram Send one message, then edit it. If a message lands between the progress draft and the answer, the draft reposts below it (post-new-then-delete-old) instead of scroll-jumping the client.
Mattermost Editable draft post. Tool activity folds into the same draft-style post.

Channels without safe edit support fall back to typing indicators or final-only delivery. See Streaming and chunking for the full runtime-behavior breakdown per channel.

Finalization

When the final answer is ready, OpenClaw tries to keep the chat clean:

  • If the draft can safely become the final answer, OpenClaw edits it in place.
  • If the channel uses native progress streaming, OpenClaw finalizes that stream when the native transport accepts the final text.
  • Otherwise (media, an approval prompt, an explicit reply target, too many chunks, or a failed edit/send) OpenClaw sends the final answer through the normal channel delivery path instead of overwriting the draft.

The fallback is intentional: sending a fresh final answer beats losing text, mis-threading a reply, or overwriting a draft with a payload the channel cannot represent safely.

Troubleshooting

I only see the final answer.

Check that channels.<channel>.streaming.mode is progress for the account or channel that handled the message. Some group or quote-reply paths disable draft previews for a turn when the channel cannot safely edit the right message.

I see the label but no tool lines.

Check streaming.progress.toolProgress. If it is false, OpenClaw keeps the single draft behavior but hides tool and task progress lines.

I see a fresh final message instead of an edited draft.

That is the safety fallback described in Finalization. It can happen for media replies, long answers, explicit reply targets, old Telegram drafts, missing Slack thread targets, deleted preview messages, or failed native stream finalization.

I still see standalone progress messages.

Progress mode suppresses default standalone tool-progress messages whenever a draft is active. If standalone messages still appear, confirm the turn is actually using progress mode and not streaming.mode: "off" or a channel path that cannot create a draft for that message.

Teams behaves differently from Discord or Telegram.

Microsoft Teams uses a native stream in personal chats instead of the generic send-and-edit preview transport, and maps streaming.mode: "block" to Teams block delivery because it has no draft-preview block mode like Discord and Telegram.