Skip to content

acpmux: agent-to-agent messages show their sender; sub-sessions show in the transcript and summary - #22827

Merged
teamleaderleo merged 52 commits into
feat-cmux-nextfrom
cmux/subsession-visibility
Oct 21, 2026
Merged

teamleaderleo merged 52 commits into
feat-cmux-nextfrom
cmux/subsession-visibility

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Agent-to-agent work in acpmux is now visible in the agent pane, and a lane's acpmux send report draws as a message from that lane, not as the person's prompt.

What changes

  • Who sent a prompt. When a connection proves it runs inside an acpmux session (the caller token acpmux puts in that session's env) and prompts a different session without a provenance of its own, the daemon records {kind: "session_message", from, fromName, to} on the user_message and on its queued record. The pane draws it as "Received message from ›", and the name opens that chat. The person's connections, prompts to the sender's own session, the acpmux TUI and a shell's acpmux send stay the person's. A provenance the sender gives is still checked and kept as before. This is the daemon-side fix the cmux-next agent pane: received agent messages are one "Received message from" line; nothing auto-folds #22761 review asked for in place of a client-name guess.
  • Sub-session messages. A parent's send_message waits behind the child's running turn by default (deliver: after_turn). next_step is opt-in and delivers into the running turn when the child's agent can take a message mid-turn. The reply says which happened, with the queue's length.
  • What a child waits on. get_session and the summary say what a sub-session waits on the person for (a question or a permission), plus its plan step and latest tool.
  • Where the user sees the child. start_session's reply says the child is listed under the parent chat.
  • The child's chat names its sender (parent, sub-session, ancestor or descendant), with the sender's short name.
  • Transcript and summary. Sub-session tool calls draw as cards (started, sent, waiting, reply). The summary lists sub-sessions after subagents, and a row opens the child's chat.

Tests

  • Failing first: cmux-tui/crates/acpmux/tests/subsessions_delivery.rs (e02cbe7, a parent's message waits behind a working child's turn) and tests/hub_integration/prompt_provenance.rs a_prompt_sent_from_inside_another_session_records_that_session_as_its_sender (bf479a0). Both are expected to fail on base and pass on the head.
  • Webview: incomingMessage.test.ts, subsessionCalls.test.ts, subagents/subsessions.test.ts.

Observed / Not run

  • Observed locally: scripts/web-lint.sh passed, prepush-gate.py found no new violations, and cargo fmt is clean.
  • Not run: the Rust tests and the webview tests. Agents don't compile or run tests on Leo's Mac, so CI and the fleet are the first runs. The red-on-base and green-on-head results for the two failing-first tests come from CI.
  • Not done: the Swift side (an open-tab action for a child chat, sidebar nesting). The Swift app also doesn't read session_message yet, so its own transcript still shows such a prompt as the person's.

No capture: the visible change is the agent pane's webview (sub-session cards, "Received message from …", the summary's sub-session rows), which the gallery advisory run captures; the only native path is build-agent-pane-web.sh adding the cards' stylesheet to the pane bundle.

Changelog

  • Changed: Messages that agents send each other (sub-session messages and acpmux send from inside a session) show as "Received message from …" from the sending chat. Sub-sessions show as cards in the transcript and in the summary.

Agent session: cosmic-gray

🤖 Generated with Claude Code


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


Summary by cubic

Acpmux now shows agent-to-agent messages with their sender in the agent pane, and sub-sessions appear in the transcript and summary instead of reading as the person's own prompts.

  • A prompt sent from inside another session with no provenance of its own is recorded as session_message and drawn as "Received message from "; sub-session family messages draw as coming from the sending chat, and the pair guard counts these.
  • send_message queues behind the target's running turn by default (deliver: after_turn); deliver: next_step is opt-in, and a child's next_step to its parent waits for the turn to end since a steer can cancel the parent's tool call. The reply says which happened and the queue length.
  • Running turns expose their current activity (latest tool title, plan step), and session summaries, session rows and get_session report what a sub-session waits on the person for (question or permission); an ancestor may answer a question when the person enables that. These fields are masked for peers and in rows handed to a parent's agent and stay optional in the protocol spec, as schemars emits them; session rows carry the summary's whole field set, watching included.
  • Sub-session tool calls draw as cards in the transcript, including a running call in a live turn as its own card so the working line never names it, and a settled run holding a sub-session card stays unfolded. The summary lists sub-sessions under subagents; names open the child's chat.

Not included: Swift-side support (open-tab action, sidebar nesting); the Swift app still shows session_message prompts as the person's.

Written for commit 610e3f8. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 12 commits October 20, 2026 16:55
…(failing)

send_message always queued behind the child's running turn, so a
parent's correction could sit unread for the whole turn, and the tool
said only "Sent.". get_session said "running" but not what the child
was doing, and start_session's reply carried shown:false, which a
parent read as "the user cannot see it".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…step

- send_message delivers into the child's running turn by default
  (deliver: next_step, read at its next tool step, the way Claude Code
  reads a person's mid-turn message); after_turn queues, interrupt
  stops the turn. An agent that takes no prompt mid-turn gets it when
  the turn ends. The result says how it went (delivery, position,
  queueLength, steering), and the tool's text says when it is read.
- The running turn records what it does: its latest tool call's title
  and its plan's step in progress (turn.activity, turn.planStep).
  get_session/list_sessions rows carry state, stateSince and a doing
  line, masked like the other text.
- start_session answers with the row get_session reads, not a session
  summary whose shown:false meant only that no client had it open.
- A family message's provenance says who the sender is to the
  receiver (fromRole parent, subsession, ancestor, descendant) and its
  short name, for the receiver chat's label.
- send_message moves to hub/subsession_send.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
get_session and list_sessions rows gain waitingOn (question or
permission), and doing names the question. Only the person answers
either, in the app; the tool text tells the parent agent to relay it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
A parent's message to its sub-session (and the child's first prompt, and a
report from a child) arrives with provenance kind subsession_message. The
chat now draws it as an incoming message card from its sender: its short
name (else its full name), who it is to this chat ("Parent · coordinator",
"Sub-session · tests"), and an Open that opens that chat beside this one.

The catalog also gains the strings the sub-session cards and summary rows
use, in all 21 pane locales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
Calls to the cmux-subsessions tools draw as their own cards instead of the
generic MCP row (a new "subsession" tool group, checked before the MCP one):
start_session as "Started sub-session tests" with its live state from the
session list (working with what it does now, needs input with what it waits
on, failed, done, N queued); send_message as "Sent to tests: <first line>"
with how it was delivered; wait_for_sessions as each sub-session's reply or
state. Running calls are one pending line; refused calls and the server's
other tools keep the generic row. A sub-session's name opens its chat
beside this one through chat.offer.open.

The summary card's Subagents section also lists the chat's sub-sessions and
theirs, indented, with state, unread dot, queue count and the doing or
waiting line; the card shows itself for a chat with sub-sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
SessionSummary gains waitingOn (question or permission) and
waitingPrompt (a question's first prompt), so the Summary panel and
sub-session cards say what a child needs without a tool call.
get_session's doing line reads them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…next_step is opt-in

A steered prompt can cancel the tool call the receiving agent is running (the coordinator's
chat, 2026-10-20), so a sub-session message waits for the turn to end unless the sender passes
deliver: next_step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
… as its sender

Failing test first: today the daemon records no provenance for it, so a lane's
`acpmux send` report draws as the person's own prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…n's message

When a connection proved it runs inside an acpmux session (its caller token)
and sends a prompt to a different session with no provenance of its own, the
daemon records {kind: session_message, from, fromName, to}. The person's
connections, prompts to the sender's own session and peer-forwarded prompts
stay unmarked, so the TUI and a shell's `acpmux send` remain the person's.
The agent pane draws it as a received message from that session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…sion-visibility

# Conflicts:
#	webviews/src/agent-session/acpmux/App.tsx
#	webviews/src/agent-session/acpmux/summary/SummaryCard.tsx
The merge of feat-cmux-next lost compaction.failedWithError and reordered the
catalog. The catalog is now the base's text with this branch's 21 new strings
added at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 21, 2026
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 02:45 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-3ynan created for this PR by the cmux coordinator.

teamleaderleo and others added 5 commits October 20, 2026 20:04
…sion-visibility

# Conflicts:
#	cmux-tui/crates/acpmux/src/hub/subsessions.rs
Failing test first: the agent pair guard counts agent_message and
subsession_message, not the new session_message, so a lane repeating the same
report to another session is never paused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…hild never steers into its parent

- hub/agent_pairs.rs: a prompt a session sends from inside itself
  (session_message) counts toward its pair like any agent message.
- hub/subsession_send.rs: a child's deliver: next_step to its parent waits for
  the parent's turn to end instead, since a steer can cancel the parent's tool
  call; the tool text says so.
- hub/subsessions.rs: a blank line no longer splits KeptWorktree's doc comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray
…sion-visibility

# Conflicts:
#	webviews/src/agent-session/acpmux/App.tsx
#	webviews/src/agent-session/acpmux/conversation/IncomingMessageCard.gallery.ts
#	webviews/src/agent-session/acpmux/conversation/IncomingMessageCard.tsx
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 03:07 — with GitHub Actions Inactive
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 03:26 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 610e3f8: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr22827 -f ref=cmux/subsession-visibility -f platform=macos -f backend_mode=local

Gallery before/after for 610e3f8: 16 states rendered, 5 images differ, 1435 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 39621210572 -R manaflow-ai/cmux -n gallery-advisory-22827-610e3f8721e1a66ce3729d0fdb7d1905ff666ab9 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/standard Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/wide Apple System Colors unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors Light unchanged 0% own App.tsx
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/scrolled-to-end Apple System Colors unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors Light unchanged 0% own App.tsx
agent-pane.composer-floats/composer-grown Apple System Colors unchanged 0% own App.tsx
agent-pane.docked-chat/new-chat Apple System Colors Light unchanged 0% own App.tsx
agent-pane.docked-chat/new-chat Apple System Colors unchanged 0% own App.tsx
agent-pane.docked-chat/after-turn Apple System Colors Light unchanged 0% own App.tsx
agent-pane.docked-chat/after-turn Apple System Colors unchanged 0% own App.tsx
agent-pane.docked-chat/working Apple System Colors Light unchanged 0% own App.tsx
agent-pane.docked-chat/working Apple System Colors unchanged 0% own App.tsx
agent-pane.docked-chat/typing-in-dock Apple System Colors Light unchanged 0% own App.tsx
agent-pane.docked-chat/typing-in-dock Apple System Colors unchanged 0% own App.tsx
agent-pane.docked-chat/long-title Apple System Colors Light unchanged 0% own App.tsx
agent-pane.docked-chat/long-title Apple System Colors unchanged 0% own App.tsx
agent-pane.incoming-message/subsession Apple System Colors Light new 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/subsession Apple System Colors new 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/messages Apple System Colors Light unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/messages Apple System Colors unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/opened Apple System Colors Light changed 0.0024% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/opened Apple System Colors changed 0.001% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/details Apple System Colors changed 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/details Apple System Colors Light unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/mid-turn Apple System Colors Light unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/mid-turn Apple System Colors unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/reply Apple System Colors Light unchanged 0% own IncomingMessageCard.gallery.ts
agent-pane.incoming-message/reply Apple System Colors unchanged 0% own IncomingMessageCard.gallery.ts

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

Unclear: web / react-apps-check (1) failed: no known signature; failed step: Fail on the gate checks.

CI failed on 610e3f8721 (run 39621210853 attempt 2): 3 unknown.

Job Verdict Why
web / react-apps-check (1) unknown no known signature; failed step: Fail on the gate checks
web / react-apps-check (2) unknown no known signature; failed step: Test webviews
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Not re-run automatically: web / react-apps-check (1), web / react-apps-check (2), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: web / Web status; base red: the same failure on the base 9206eac; does not block
red: web / react-apps-check; base red: the same failure on the base 9206eac; does not block
red: web / react-apps-check (1); base red: the same failure on the base 9206eac; does not block
red: web / react-apps-check (2); NEW: green on the base 9206eac; do not merge until green; see lane-rules

CI fast guards failed on 610e3f8721 (https://github.com/manaflow-ai/cmux/actions/runs/39621210853). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally.

Tour of 610e3f8721 (run): no media. The tour job failed before the tour ran (build or setup); the run log has the output.

@teamleaderleo

This comment has been minimized.

Conflict only in IncomingMessageCard.tsx header comment: kept both the
Details note from #22895 and the sub-session relation note.

Agent-Session: 01a15ba9-9614-7832-8e39-d8ca0407c193
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 04:04 — with GitHub Actions Inactive
…2827

# Conflicts:
#	cmux-tui/crates/acpmux/src/hub/mod.rs
#	cmux-tui/crates/acpmux/src/hub/subsessions.rs
#	cmux-tui/crates/acpmux/src/subsession_mcp.rs
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 14:10 — with GitHub Actions Inactive
SessionDetail flattens SessionSummary, so schemars lists waitingOn,
waitingPrompt and base's watching on it as well; the spec had none of
them there. waitingOn's description keeps its doc comment's line break,
as schemars emits it. The waiting_on comment now says an ancestor may
answer a question when the person turned that on (#22740).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray
@cursor

cursor Bot commented Oct 21, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 14:14 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 97c8f08

Covers the base merges since 814adb4 (App.tsx; #22740's sub-session questions in hub/mod.rs, hub/subsessions.rs, subsession_mcp.rs, with the tool wording now saying only the person allows a permission while a question may be answered with answer_question), the gallery fix for subsession-cards#summary at popover width, and the spec fix: SessionDetail carries every SessionSummary field (incl. base's watching, missing since #21921) and waitingOn's description keeps its line break, as schemars emits them.

…2827

# Conflicts:
#	webviews/src/agent-session/acpmux/App.tsx
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 1da7852

Base merge only since 97c8f08: App.tsx keeps base's VirtualTranscript block (needsYou) inside the PR's SubsessionContext.Provider; base's sessionList.ts removals leave no callers; catalog in base order; toml equals base.

@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 14:41 — with GitHub Actions Inactive
…2827

# Conflicts:
#	webviews/src/agent-session/acpmux/App.tsx
@teamleaderleo
teamleaderleo temporarily deployed to cmux-tui-merge-tree October 21, 2026 14:51 — with GitHub Actions Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 8f65b51

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (independent subagent, correctness first): SHIP at 610e3f8

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Merge check at 610e3f8: the build-script change (scripts/cmux-next/build-agent-pane-web.sh) is covered by cmux-next Release compile (Xcode 26), web bundles and generated drift, all green. swift test was cancelled and generated files is still queued on the Mac pool; the diff has no Swift. Remaining reds are base reds: gallery health (agent-pane.artifact-panel "Open preview" and composer fast-mode waitFor states, the same ones failing on other PRs; this PR adds neither), fast gates, clippy on changed cmux-tui packages, defaults-snapshot. Merges cleanly with current feat-cmux-next. Merging.

@teamleaderleo
teamleaderleo merged commit afababb into feat-cmux-next Oct 21, 2026
@teamleaderleo
teamleaderleo deleted the cmux/subsession-visibility branch October 21, 2026 16:31
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
…bility-followups

#22827 landed as one squash commit, so this branch's older copy of its
commits conflicted throughout. Every file this PR's own commits never
touched now matches feat-cmux-next; the diff is only chat.offer.open's
Mac handler, the family check and their tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
* Agent pane: a turn's end leaves its reply where it was

A followed chat's reply slid 4px down at every turn's end, in Chromium and
WebKit. The running turn's last line (`below`) is the footer's height so
the footer can take its place, but the reply over it kept the 8px message
gap and only switched to the footer's 4px meta gap (and lost its 34px
floor) once the footer came. A reply over that line is now
`before-footer` too, in the estimate (model.ts isBeforeFooter) and in the
row's class (App.tsx), from the one predicate.

Seen as the WebKit-only 1.5px drop in stream-jitter's "a queued prompt
sent as the next turn" on #22827's shards: under load the turn's end and
the queued prompt's arrival land a frame apart, and the 4px shrink's
downward glide shows. On Linux WebKit under 4-way load it failed 1 run in
12 on base and 0 in 36 with this.

New: stream-jitter "a turn that ends leaves its reply where it was" (red
on base: 4px Chromium, 3px WebKit) and a rowEstimates case (red on base:
303.75 vs 299.75).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-f5e3-77e3-a3e6-159012f35d5f&host=cmux16

* webviews tests: stream-jitter waits for the view to rest, not a fixed time

check:fixed-waits counted 27 waits against the file's baseline of 22: the
new turn-end test's three waitForTimeout calls and its uses of open() and
stream(). open() and the turn-end test now wait for the view to rest (its
offset held and no glide on the thread for 6 painted frames) and for the
footer row; stream()'s chunk pacing is the behavior and says so in a
fixed-wait comment. The file is down to 9 and its baseline row with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-f5e3-77e3-a3e6-159012f35d5f&host=cmux16

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
…ffer.open) (#23159)

* test(acpmux): a parent's message waits behind a working child's turn (failing)

send_message always queued behind the child's running turn, so a
parent's correction could sit unread for the whole turn, and the tool
said only "Sent.". get_session said "running" but not what the child
was doing, and start_session's reply carried shown:false, which a
parent read as "the user cannot see it".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* feat(acpmux): sub-session messages reach a working child at its next step

- send_message delivers into the child's running turn by default
  (deliver: next_step, read at its next tool step, the way Claude Code
  reads a person's mid-turn message); after_turn queues, interrupt
  stops the turn. An agent that takes no prompt mid-turn gets it when
  the turn ends. The result says how it went (delivery, position,
  queueLength, steering), and the tool's text says when it is read.
- The running turn records what it does: its latest tool call's title
  and its plan's step in progress (turn.activity, turn.planStep).
  get_session/list_sessions rows carry state, stateSince and a doing
  line, masked like the other text.
- start_session answers with the row get_session reads, not a session
  summary whose shown:false meant only that no client had it open.
- A family message's provenance says who the sender is to the
  receiver (fromRole parent, subsession, ancestor, descendant) and its
  short name, for the receiver chat's label.
- send_message moves to hub/subsession_send.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* feat(acpmux): a parent reads what its sub-session waits on the user for

get_session and list_sessions rows gain waitingOn (question or
permission), and doing names the question. Only the person answers
either, in the app; the tool text tells the parent agent to relay it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(acpmux): start_session's reply names where the user sees the child

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* feat(agent-pane): a sub-session's chat names who wrote to it

A parent's message to its sub-session (and the child's first prompt, and a
report from a child) arrives with provenance kind subsession_message. The
chat now draws it as an incoming message card from its sender: its short
name (else its full name), who it is to this chat ("Parent · coordinator",
"Sub-session · tests"), and an Open that opens that chat beside this one.

The catalog also gains the strings the sub-session cards and summary rows
use, in all 21 pane locales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* feat(agent-pane): sub-session cards in the transcript and the summary

Calls to the cmux-subsessions tools draw as their own cards instead of the
generic MCP row (a new "subsession" tool group, checked before the MCP one):
start_session as "Started sub-session tests" with its live state from the
session list (working with what it does now, needs input with what it waits
on, failed, done, N queued); send_message as "Sent to tests: <first line>"
with how it was delivered; wait_for_sessions as each sub-session's reply or
state. Running calls are one pending line; refused calls and the server's
other tools keep the generic row. A sub-session's name opens its chat
beside this one through chat.offer.open.

The summary card's Subagents section also lists the chat's sub-sessions and
theirs, indented, with state, unread dot, queue count and the doing or
waiting line; the card shows itself for a chat with sub-sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* feat(acpmux): a session's summary says what it waits on the person for

SessionSummary gains waitingOn (question or permission) and
waitingPrompt (a question's first prompt), so the Summary panel and
sub-session cards say what a child needs without a tool call.
get_session's doing line reads them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(acpmux): send_message queues behind the running turn by default; next_step is opt-in

A steered prompt can cancel the tool call the receiving agent is running (the coordinator's
chat, 2026-10-20), so a sub-session message waits for the turn to end unless the sender passes
deliver: next_step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* test(acpmux): a prompt from inside another session names that session as its sender

Failing test first: today the daemon records no provenance for it, so a lane's
`acpmux send` report draws as the person's own prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(acpmux): a prompt sent from inside another session is that session's message

When a connection proved it runs inside an acpmux session (its caller token)
and sends a prompt to a different session with no provenance of its own, the
daemon records {kind: session_message, from, fromName, to}. The person's
connections, prompts to the sender's own session and peer-forwarded prompts
stay unmarked, so the TUI and a shell's `acpmux send` remain the person's.
The agent pane draws it as a received message from that session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(agent-pane): restore the base's strings the merge dropped

The merge of feat-cmux-next lost compaction.failedWithError and reordered the
catalog. The catalog is now the base's text with this branch's 21 new strings
added at the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* test(acpmux): a session repeating itself with acpmux send is paused

Failing test first: the agent pair guard counts agent_message and
subsession_message, not the new session_message, so a lane repeating the same
report to another session is never paused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(acpmux): review fixes: the pair guard counts session_message; a child never steers into its parent

- hub/agent_pairs.rs: a prompt a session sends from inside itself
  (session_message) counts toward its pair like any agent message.
- hub/subsession_send.rs: a child's deliver: next_step to its parent waits for
  the parent's turn to end instead, since a steer can cancel the parent's tool
  call; the tool text says so.
- hub/subsessions.rs: a blank line no longer splits KeptWorktree's doc comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* fix(agent-pane): close the gallery's sub-session variant the merge left open

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15ba9-9614-7832-8e39-d8ca0407c193&host=cosmic-gray

* agent-pane: ship SubsessionCallCard.css in the pane bundle

The sub-session card imports its own sheet, and build-agent-pane-web.sh
refuses a pane import it does not concatenate into the page styles.

Agent-Session: 01a15ba9-9614-7832-8e39-d8ca0407c193
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* agent-pane strings: keep base's key order, adding only this PR's keys

The local key-wise merge driver had reordered the catalog, so GitHub's
text merge conflicted with every base change near it.

Agent-Session: 01a15ba9-9614-7832-8e39-d8ca0407c193
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(acpmux): a peer reads a summary's new turn activity, plan step and waiting prompt masked

Review of #22827: turn.activity is a tool call's title, often a command
with its arguments, and goes to every peer in the session list, as do
turn.planStep and waitingPrompt. Mask them as turn.prompt is (hq#2509).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-663f-7650-b9f7-64d198c6b88b&host=cosmic-gray

* cmux NEXT agent pane: a click on a sub-session opens its chat (chat.offer.open)

The transcript's sub-session cards, the Subagents summary and a received
message's sender all ask the host to open that chat with chat.offer.open,
but no Mac host answered it, so the click did nothing. The pane now
answers it: the tab that shows the session already is shown and focused,
else the chat opens in the chat's side pane (or a split right of it),
focused, as a side chat does. Nothing opens unless the person clicks.

It opens only a session this pane made or one of the chat's family: a
sub-session its agent started at any depth, or the session that started
it. The turn-state watch now mirrors acpmux's startedBy links for that
check. No CmuxNextApp source lines are added.

Ported from the preserved WIP commit 5a8f7c2 (AgentPaneOfferOpen and
the sub-session tree), trimmed to the open path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* chat.offer.open reaches the Mac handler; family check passed per pane

The page's own chat.offer.open action (which callNative prefers) now asks
the app first (AgentPaneOfferOpen: focus the session's tab or open it
beside the chat) and falls back to chat.sideChat, then selecting it here.

The family check is a closure on AgentPaneHeaderHooks supplied by
AgentTabStore from its turn-state store, replacing the global static the
turn-state feed set on every start. An opened session's existing tab is
looked up on the chat's own acpmux host, so a Chief chat's sub-session tab
is found. Tests inject their own family check, cover a chat inside a
startedBy cycle, and parse startedBy from the feed's page, change and purge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* Refuse a non-family offer.open with its own code so the page opens nothing

The page fell back to chat.sideChat and then to opening the session in the
chat's own tab on any refusal, so a click on a session outside the chat's
family still replaced the chat. A refusal now carries chat.offer.refused,
which the page takes as final; unsupported still means an older host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* agent-pane strings: keep base's key order, adding only this PR's keys

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* SDK resource-api descriptors: take base's catalog hash

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* Open a Cloud VM chat's children on click, as chat.sideChat does

chat.offer.open refused a remote chat's children: its guard read only the
pane's scope and the app's mirrored startedBy links, while a remote chat's
links live in RemoteAgentSessionLinks. Use AgentPaneSideChat.holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

* Open a Cloud VM chat's parent on click too

On base the page fell back to opening it in the chat's tab; with the
refusal it opened nothing. The remote links know the parent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

This branch was previously deployed

4 inactive (2 outdated) deployments
ci-routing-agent — 610e3f87 Deployed Oct 21, 2026 by github-actions[bot]
cmux-tui-merge-tree — 610e3f87 Deployed Oct 21, 2026 by teamleaderleo
artifacts — 1372d567 Deployed Oct 21, 2026 by teamleaderleo
sentry-dsyms — 1372d567 Deployed Oct 21, 2026 by teamleaderleo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant