[BUG] Workflow log() output is invisible for background runs — /workflows and task panel filter workflow_log out
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
The Workflow tool's model-facing description documents:
log(message: string): void — emit a progress message to the user (shown as a narrator line above the progress tree)
For a background-launched workflow (the default launch mode), this is not true on any live surface. log() messages are emitted and collected, but:
- the
/workflowsprogress view never renders them (its phase builder consumes onlyworkflow_agent/workflow_phaseprogress entries), - the task panel below the input box filters them out explicitly (
.filter((P) => P.type !== "workflow_log")), - the inline transcript entry for the tool call shows only the static result card ("Running in background · /workflows to monitor and save"),
- when the progress array grows past its cap,
workflow_logentries are the first thing trimmed.
The only place the messages ever surface is the logs array of <session-dir>/workflows/<runId>.json, written after the run completes — useless for watching a run.
Root cause, from reading the v2.1.201 bundle: the narrator-line renderer exists and matches the tool description (latest log line with a pointer above the phase progress groups, previous two dimmed, under verbose || isTranscriptMode), but it is wired as the Workflow tool's renderToolUseProgressMessage, which only renders while the tool use is pending. The Workflow tool returns {status: "async_launched"} immediately, so for background runs this renderer is unreachable — the run's subsequent workflow_log progress events route into the background task's state, where every consumer filters them out.
The docs page (https://code.claude.com/docs/en/workflows) tells users to watch runs in /workflows, which is precisely the surface that drops the messages.
What Should Happen?
log() output should be visible somewhere while a background workflow runs — ideally the latest narrator line in the /workflows progress view and/or the expanded task panel entry, matching what the tool description already promises. Failing that, the Workflow tool description should stop telling models the output is shown to the user, so models don't design run narration around a channel users never see.
Error Messages/Logs
# No errors — the messages are silently dropped from every live surface.
# After completion they appear only in the run's state file:
# ~/.claude/projects/<project>/<session>/workflows/<runId>.json → "logs": [...]
Steps to Reproduce
- Ask Claude to run this workflow (or invoke the Workflow tool directly):
``javascriptheartbeat ${i}/12 — this line should be visible somewhere
export const meta = { name: 'log-visibility-repro', description: 'Emit narrator lines to test visibility' }
for (let i = 1; i <= 12; i++) {
log()tick:${i}
await agent('Reply with the single word: ok', { label: })``
}
return 'done'
- While it runs, check
/workflows(run view and agent drill-down), the task panel (down arrow → Enter → expand), and Ctrl+O transcript mode. - Observe: no heartbeat line appears anywhere.
- After completion, all 12 lines are present in
~/.claude/projects/<project>/<session>/workflows/<runId>.jsonunderlogs.
Observed in practice with a long-running orchestration workflow that emits a one-line status board through log() at every state transition: the run works, but users watching /workflows see none of the narration and conclude logging is broken.
Claude Model
Other
Is this a regression?
I don't know
Claude Code Version
2.1.201 (Claude Code)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other (tmux)
Additional Information
Impact: the tool description tells every model that log() is user-visible, so models design workflow narration around it — progress boards, status lines, "notable events" summaries. For multi-hour orchestration runs this removes the only phase-independent way to tell users where the run is. The /workflows phase sidebar and agent rows render fine; it's specifically the workflow_log stream that has no consumer.