Agent pane: a tool's notice is one received line with its severity, sender, machine and title

TE
4d ago
+1125-29

Leo, on a base-red watch page that landed in a chat as a raw user bubble ("[tell-coordinator from base-red-watch on …] FIRE … fast tier failed on 3 PRs … land the fix first."):

i was wondering about this. acpmux/cmux-next should be able to allow you guys to make (and subsequently nicely render) this sort of thing

This is the transcript piece of that design: a tool's or reconciler's notice (a base-red FIRE, an autoland LANDED, a queue WARN) draws as one received line instead of the person's bubble.

What changes

  • Reading (conversation/agentNotice.ts, incomingMessage.ts): acpmux's notice provenance ({kind: "notice", from: "fromAgent", fromName, notice: {sender, host?, severity, title, links?}}) is a received message with its notice. The body drops the rendered [notice from … · FIRE] head and the Links: line. Two older forms read the same way, but only from acpmux send at a shell or its outbox, never from a prompt typed in the pane: the CLI's rendered head with no provenance (an older daemon), and today's [tell-coordinator from X on HOST] FIRE|WARN … page (first sentence becomes the title). A tell-coordinator message without FIRE/WARN reads as that sender's message.
  • Fallback: a provenance kind this page doesn't know, from an agent (from is fromAgent or acp:…) with a fromName, reads as that agent's message, not the person's bubble. person_message and the other kinds the page already knows are unchanged.
  • Row (IncomingMessageCard.tsx, NoticeMark.tsx): the same received line (DisclosureRow, SenderName). The icon column shows the severity mark: fire is a filled red disc, warn an amber triangle, info a quiet ring. None of them animate. Then the sender, its machine (the existing · host style), and the title in the rows' tone. Opened: the body in the same Markdown renderer, then the links inline on one line, named as their chips would be (#32827, run 1902234…, else the label or host and path tail).
  • Fold (LaneNoticeBatch.tsx, MessageGroupHead.tsx, messageRuns.ts): notices next to each other join the "Received N" row. When every member is a notice it reads "Received N notices" (new strings in Localizable.xcstrings), and when a fire is among them the head shows the fire mark. A fire notice ends a message run, so it never folds into a "Sent N messages, …" line.
  • Gallery agent-pane.notice-row (NoticeRow.gallery.ts) has three looks via theme.noticeLook (noticeLook.ts): mark (default), tag (the sender's agent mark plus a small FIRE/WARNING word before the title, like Codex's P1 finding), and tint (mark plus a coloured title). States: single, single-open, fold, fold-open, legacy, before.

I picked mark. It keeps the received-message family's grammar (one icon column, sender, then the text), and the red disc is the one thing that differs, so a fire is easy to spot among quiet lines. tag spends width on a word the mark already says. tint colours a whole title red, which reads louder than the rest of the transcript.

Design spec: leo-workspace design/chat-transcript.md (surface chat-transcript). This follows "Never draw a system or agent-to-agent notice as the person's own bubble", "One icon column", "Never light up or dim a received message on hover", and "Never draw a PR chip row or any link-chip row on transcript messages". Because of that last rule, links render inside the message text, not as a separate chip row. References compared: claude/live/transcript-received-messages-group, claude/live/transcript-peer-session-message, claude/live/transcript-received-message-expanded, codex/web/inline-code-review, cmux/live/transcript-unobtrusive-message-notifications, claude-mobile/live/raw-cross-session-message (anti-pattern).

Visual

Captures of agent-pane.notice-row (synthetic data) follow in a comment.

Tests

  • conversation/agentNotice.test.ts: provenance notice, invalid notice fields, unknown-kind fallback (and person_message staying the person's), the rendered head from a shell only, tell-coordinator FIRE/WARN/plain, FIREwall not being a FIRE, and link chip labels.
  • conversation/NoticeRow.test.tsx (render): the fire line's mark, sender, host and title; opened body without the head or Links: line, with both links; a fold of three reading "Received 3 notices" with the fire mark on its head.
  • Red first: commit 1 adds the tests, which fail on base (no notice reading, no row). Commit 2 makes them pass.

Observed / Not run

  • Ran locally: the two new suites, plus incomingMessage, InboxNoticeCard, laneReport, agentMessages, pendingMessages, messagesRows, queuedMessages and the gallery entries test (all pass), and scripts/web-lint.sh (passes).
  • Not run locally: the full webview suite and browser tests (left to CI).

Changelog

  • Added: notices from tools and reconcilers (a failing base, a landed PR, a queue warning) show in an agent chat as one line with their severity, sender, machine and title, instead of a raw message bubble.

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Tools' and reconcilers' notices (a failing base, a landed PR, a queue warning) now show in an agent chat as one received line with their severity, sender, machine, and title, instead of a raw message bubble. A notice of a title alone still draws a row, and Find, Copy, and export see its title; a link's destination can never close its Markdown link and start another.

Reading

  • agentNotice.ts reads acpmux's notice provenance and the CLI's rendered head or tell-coordinator's FIRE/WARN page from a shell's send; a tell-coordinator message without FIRE/WARN reads as that sender's message. Link destinations percent-encode ( ) < > and spaces, and the Links line keeps commas and parentheses inside a URL.
  • An unknown provenance kind from an agent with a fromName falls back to that agent's message, never the person's bubble; person_message and known kinds are unchanged.

Rendering

  • Each notice draws as a received line with a severity mark (filled red disc, amber triangle, quiet ring), sender, machine, and title; opening shows the body and links inline, without the rendered head or Links: line. The title reads in the rows' tone and Find highlights it on the line.
  • Consecutive notices fold into a "Received N notices" row whose head shows a fire mark when one is present; a fire never folds into a "Sent N messages" run. A title-only notice is never an empty row.
  • Default look is mark, with tag and tint as gallery variants.