cmux NEXT: Chief messages the agent chats the person started, restored ones included

Merged
AU
10d ago
+1325-51

Fixes #25571

A Chief can now message the agent chats the person started in the app (nudge, steer, ask), not only its own subagents. This includes a chat restored at launch that no tab has shown yet.

Stacked on https://github.com/manaflow-ai/cmux/pull/23074. That PR makes agents chat send|read|state find a chat in the app's own acpmux when the caller's acpmux is another one, as a Chief turn's is (its home's). This branch merges its head (8610c1b435). Until 23074 lands, the diff below includes its 13 files. This PR's own changes are the commits c0e047c6fe and 2b875697d9. Land 23074 first; this PR then shrinks to those commits.

What changed

  • Chief tool: a Chief turn keeps agents_chat_send, agents_chat_read and agents_chat_state among its cmux MCP tools. They are listed in session_dir::CHIEF_CMUX_TOOLS and in acpmux's mirror agent_tools::CHIEF_TURN_TOOLS, which harness.rs keeps equal. Before this change the turn's settings denied every other cmux tool, so a Chief had no way to reach a GUI chat.
  • Chief instructions (prompt.rs, Home rules):
    • The chat id is the acpmux session of a conversation tab: extra.conversation.agent_session.session in agents_snapshot. The daemon keeps that for restored tabs too.
    • The send starts a turn there as the Chief's message.
    • agents_chat_state, agents_wait and agents_chat_read follow it.
    • Subagents stay tell.
  • CLI/MCP verb: cmux agents chat send <chat> <text> and MCP agents_chat_send already existed. With 23074 they also reach the app's acpmux. This PR does not change them.
  • Restored, unvisited chats: these need no app change. acpmux keeps the session after a restart, and a prompt resumes its harness (session/load). The app builds a tab's page only when the tab is first shown, and that page then reads the transcript, the new turn included.
  • plans/cmux-next/cli-gui-parity.md notes the Chief's chat tools.

Defaults I chose (no human decision was available)

  • "Submitted as a user turn" means the send is the chat's next turn, a session/prompt that starts a turn, or steers the turn already running. It does not mean the person's own words. The send stays an agent message with the Chief's provenance, under the daemon's agent message policy (verified sender, session scope, limits, the acpmux runaway-pair guard). The chat shows it as the Chief's message. Sending text as if the person typed it would be a trust-policy change. This PR changes no trust policy, so nothing went to https://github.com/manaflow-ai/cmux/issues/13742.
  • Only send, read and state: agents_chat_new and agents_chat_interrupt stay denied to a Chief turn. A Chief starts work with spawn, and stopping a person's running turn stays the person's choice.
  • The prompt rule says "when the user asks": a Chief messages a person's chat only on request.
  • A held receipt waits for the person: on held, the Chief tells the user the message waits for their release (cmux agent message release) and never says it was sent. Today a Chief turn holds no launch credential, because acpmux's credential.mint is refused (origin_gate.rs check_credential_owner allows only the verified app). Its sends are therefore the local user's: they are queued and delivered, as the tests show. Once acpmux can mint credentials, a turn in the Chief home's acpmux would be an agent whose workspace the daemon cannot tell (workspace_unknown), and its send would be held. Delivering it then needs a policy decision on #13742 (a Chief turn as the person's delegate).

Tests

  • cmux-tui/crates/cmux-tui/tests/cli/agents_chat_tools.rs a_caller_sends_to_a_restored_chat_no_tab_has_shown: a real daemon and acpmux.
    • The person's chat runs a turn, then acpmux shuts down with its agents ended and starts again, so the chat is restored with no client attached.
    • A Chief-like caller (its own acpmux elsewhere, a fake app naming the real one) reads it.
    • The caller then sends; the resumed harness runs the send as one new turn, marked agent_message, and answers.
  • Live chats: 23074's a_caller_with_its_own_acpmux_starts_and_drives_a_chat_of_the_apps_acpmux and the base's an_agent_prompts_another_chat_and_reads_its_reply_over_mcp.
  • Native/OptChat/optchat-chief/tests/cloud_app_tools.rs a_chief_turn_keeps_the_tools_that_message_agent_chats: a Chief turn's cmux tool denials leave the chat send, read and state tools and deny agents_chat_new, agents_chat_interrupt and app actions. It fails on the base, where every agents_chat_* tool is denied.
  • harness.rs acpmux_built_in_turns_allow_the_same_cmux_tools keeps the two lists equal.

Observed / Not run

Observed (Rust on the rbx builder; the branch at c0e047c6fe, the merge of 23074 and this change):

  • cargo test -p cmux-tui --test cli agents_chat: 9/9 passed, including a_caller_sends_to_a_restored_chat_no_tab_has_shown and 23074's live-chat tests.
  • optchat-chief: cargo test --test cloud_app_tools --test harness passed 9/9 and 27/27, including a_chief_turn_keeps_the_tools_that_message_agent_chats and acpmux_built_in_turns_allow_the_same_cmux_tools.
  • cargo test -p acpmux --lib agent_tools: 5/6. The failure, own_servers_run_under_the_daemon_prefix, is a base finding: base commit d07f7f3a9aecd added the acpmux MCP server (acpmux-mcp) without updating that test's expected list. chief_turn_tools_contain_no_mac_app_actions passed.
  • 2b875697d9 changes only the Chief prompt text; no test reads that sentence.

Not run:

  • A live Chief turn in a GUI build messaging a real restored chat. The tagged build 25571-message-gui-agent-chats is for that dogfood.
  • A sender holding an acpmux-minted credential, because acpmux cannot mint today (see Defaults).

Changelog

  • Added: a Chief can message, nudge and read the agent chats you started, including ones restored at launch that you haven't opened yet.

šŸ¤– Generated with Claude Code