chief: agents' messages carry their sender and take the ask floor; tell(session:NAME) as the Chief
Problem
Agents that message the Chief through cmux chief -p, cmux chief send or cmux chief acp were posted as the owner (user_local). A lane's message read as the user's own words and ran under the owner's approve-all policy. The Chief also had no way to answer or message another acpmux session as itself.
Task (gaps 1 and 2 of the Chief-vs-acpmux gap study): "messages from other agents arriving via cmux chief -p / cmux chief acp must carry sender identity/class/thread and show as that agent, not as the owner (user_local), and must not inherit the owner's approve-all policy", plus "an optchat tool that sends to an acpmux session as the Chief, plus a read-only session list, with replies routed back into the Chief chat the way subagent reports are".
Change
Inbound (gap 1)
cmux_conversation::agent_senderis a new codec. A message carries its sender in itsclient_msg_idasagent~NAME~CLASS~THREAD~NONCE, and its text shows[from NAME] ā¦. This needs no new daemon op. The marker can only lower trust.- The CLI sets the sender on every send path:
cmux chief -ptakes--from NAME,--class Cand--thread T. Without--from, it usesACPMUX_SESSION_NAME.cmux chief sendusesACPMUX_SESSION_NAME.cmux chief acpreads the new_meta.acpmux.sender.
- acpmux now passes another agent's name, class and thread to the agent as
_meta.acpmux.sender, on turn prompts and on steers. cmux_chief::rules::is_owner_message_asreturns false for a marked message. The turn therefore runs under the ask floor, and its children inherit it. The Chief reads the message labelled with its session, class and thread, plus a note that it is not the user's word.
Outbound (gap 2)
tell(id: "session:NAME", message)sends to acpmux session NAME as the Chief (fromAgent: chief, classquestion). NAME's answer comes back as a[session:NAME] ā¦report. It is a newSource::Agent, which requires approval, the same way a subagent's report arrives.control(action: "sessions")lists the sessions the Chief may tell. It is read-only and allowed in ask turns.- These are refused as targets: any Chief's own turn and compactor sessions, and this Chief's subagents (tell those by
a<N>). - An ask turn may only
tellthe sessions whose messages it carries (turn_agents). So another agent or person cannot use the Chief to start a talk with a third session.
The README policy table, the tool descriptions and the golden tool list are updated.
Tests
- Red first:
another_agents_message_through_the_cli_is_that_agents_and_takes_the_ask_floor(approval_gates.rs) was committed failing in 65c8a04, then fixed. - Unit tests:
- the codec round trip and its cleaning limits;
- CLI
--fromand the env fallback; - the
chief acpsender meta; - acpmux
prompt_sender; session_tellnaming, refusals and the reply label.
- Gate checks: an ask turn may tell its own sender, is refused for another session, and may run
control sessions. A tell to an unknown session says so.
Risk
This is Chief-area code (optchat-chief brain, chief-kernel tool list), so it lands with the Chief-area checks. acpmux now adds an _meta.acpmux.sender key to session/prompt for agent-sent prompts; ACP _meta is ignored by harnesses that do not read it. The Cloud Chief wasm (backend/.../optchat-wasm) is not rebuilt here and keeps the old tool descriptions (follow-up).
š¤ Generated with Claude Code
Agent session: agent session
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Messages from other agents sent through cmux chief now carry the sending session's identity instead of posting as the owner, and the Chief can message other acpmux sessions as itself with replies routed back like reports.
Inbound attribution
- Agent-sent messages are marked in
client_msg_id(agent~NAME~CLASS~THREAD~NONCE), show as[from NAME], and can only ever lower trust, never grant owner status. The marker is honoured only on the owner's own messages: a forged marker from another person names nobody, so their turn gets no session to tell. - Their turns run under the ask floor instead of the owner's approve-all policy;
--from/--class/--threadoncmux chief -p,ACPMUX_SESSION_NAMEforsend, and_meta.acpmux.senderforacpset the sender. acpmux also passes the sender meta on the steers it sends to a running agent.
Outbound messaging
tell(id: "session:NAME")sends to an acpmux session as the Chief; the answer returns as a[session:NAME]report under the ask floor. A tell steered into a running turn waits for that turn's end, and the route is dropped after the answer.control action: "sessions"lists reachable sessions; Chief's own turn/compactor sessions, its subagents, and Chief-harness chats are refused, and an ask turn may only tell sessions whose messages it carries.