acpmux inbox notice: received lines in the transcript, less text for the agent
Leo (2026-10-31), with a screenshot of an agent chat that showed three inbox notices as the person's own bubbles: "isn't this rendered pretty terribly? why do we have this like this? why is there so much additional text?"
Takes back #28749: its inbox part only. #28749 drew an inbox_notice as a message card named "inbox" that opens to the notice's text, and folded adjacent notices into a LaneNoticeBatch ("3 inbox threads"). That is the text Leo called out, so here an inbox_notice becomes kind inbox (each thread under its real sender, the messages whole) and adjacent notices fold through mergeInboxNotices. #28749's inbox branch in incomingPrompt could no longer run and is removed. Its lane reports, their batching and LaneNoticeBatch are unchanged.
What changes
Webview. A prompt whose provenance is acpmux's inbox_notice (hub/inbox.rs, #27686) is no longer drawn as its text. incomingMessage.ts had no case for it, so it fell through to a user bubble. Now:
- Each thread is another agent's received line, as
IncomingMessageCarddraws a message: the newest sender's mark and name (a click opens that chat), the thread's label (#PRor the topic), the newest message's first line, and "+N more". A click opens the thread's new messages whole, oldest first. They come from the notice's own copy, or from_acpmux/inbox_thread(newchat.inbox.threadaction,AcpmuxDirectClient.inboxThread) without marking anything read. - Two or more threads, or notices next to each other (
mergeInboxNotices), fold into one line, "N messages from M sessions" plus the senders, in the waiting-messages group's look (PendingMessagesCard). Find, the row estimate and the open state follow the existing patterns (incomingOpened.ts,joined). - No text written for the agent is shown. A failed turn the notice started never sends the notice's text again as if the person typed it (no composer resend, as for
notice); acpmux's own turn retry (_acpmux/retry), which reruns the turn and sends nothing from the person, is still offered.IncomingMessageCardand theagent_messagecards are not restyled.
Daemon (hub/inbox.rs render).
- The instruction sentence ("They need no turn of your own: ā¦") is gone from every notice. The
inbox_readtool description says it now. - When the new messages total 4 KB or less (their text as sent), the notice holds them whole,
messagesuntrimmed: a one-line message on its thread's line, longer ones quoted under it. That fixes the agent that has noinbox_readtool and saw only a 120-character preview. - Over 4 KB, previews stay, and the header says how to read a thread from any harness:
inbox_read, oracpmux session inbox "$ACPMUX_SESSION_ID" --thread ID --mark-read(asked for by the lane that owns the Labs gating fix, #28707; it does not touchrender). - The provenance
threadskeepthreadId/new/from/promptIdsand addlabel,blocker,preview,newestAt,fromSessionand, when whole,messages. A notice logged before this change still renders: the webview reads the label and preview back from its text.
Design spec: leo-workspace design/chat-transcript.md gets the rule "Never draw a system or agent-to-agent notice as the person's own bubble" (leo-workspace PR to follow).
Screenshots
Gallery entry agent-pane.inbox-notice, 2x, synthetic names and messages. Before is the base rendering of the same three notices (variant before-six).
| Light | Dark | |
|---|---|---|
| Before: three notices in a row, as acpmux wrote them (base) | ![]() | ![]() |
| After: the same six threads, one line | ![]() | ![]() |
| After: opened, a thread of three messages opened | ![]() | ![]() |
| After: a notice of one thread, opened | ![]() | ![]() |
| After: three threads (closed) | ![]() |
Versions
Three versions are in the gallery (theme.inboxNoticeLook): group (the default, shown above), lines (a received line per thread, no head) and card (the lines in one bordered card). I picked group: it matches the spec's waiting-messages group, and six threads take one line until opened. lines reads well at three threads but stacks at six. card adds a box the rest of the transcript doesn't use.
lines | card |
|---|---|
![]() | ![]() |
I viewed every after image above, light and dark, at 2x.
Tests
cargo test -p acpmux --lib -- hub::inbox acpmux_mcp: 21 passed.a_notice_is_one_line_per_thread_blockers_first_then_the_newestnow checks the whole-text form and the new parts;a_long_notice_has_previews_and_says_how_to_read_a_thread_from_any_harnessanda_whole_notice_keeps_every_message_as_it_was_sent(a blank message keeps its quote line, an indented one its indent, the 4 KB counts untrimmed text) are new.cargo test -p acpmux --test hub_integration -- agent_inbox: 11 passed (300-message notice, blocker order, threads read whole).bun test conversation/incomingMessage.test.ts conversation/inboxNotice.test.ts: 40 passed (inbox_notice ā threads, the fallback for old notices, a notice with no thread ā hidden, the merge of adjacent notices, label rules).bun test conversation/InboxNoticeCard.test.tsx: 2 passed, both red on the first head's component: a thread read from acpmux reads again when a later notice brings new messages, and a read that finds nothing keeps the preview.- Every tracked
webviews/src/agent-session/acpmuxtest file, run one file at a time: all pass. bun run check: type check clean. The remaining reds (check:layers,check:design-tokens,vp fmt --checkandvp lintwarnings) name onlysrc/pages/settings/*, which this PR does not touch.
Observed / Not run
- Ran: everything above, on a lane VM. The screenshots come from the local gallery dev server with Playwright Chromium.
- Not run: a tagged Mac build. This changes only the webview and the acpmux daemon's notice text; there is no Swift change.
Changelog
- Changed: Messages other agents leave in a chat's inbox show as sender lines that open to the messages, not as raw notice text in your own bubble.
risk: normal (webview rendering, and the text of the agent-facing notice).
Agent session: agent session
š¤ Generated with Claude Code










