diff --git a/hive-c0re/src/agent_server.rs b/hive-c0re/src/agent_server.rs index 182e3413..9dcf468e 100644 --- a/hive-c0re/src/agent_server.rs +++ b/hive-c0re/src/agent_server.rs @@ -563,6 +563,31 @@ pub(crate) fn handle_send( // learning the label — runtime reparenting propagates for free. See // `docs/conventions.md::Recipient sentinels`. let resolved = crate::topology::resolve_recipient(agent, to); + // Validate that the resolved recipient is a known local agent or the + // special "operator" recipient. Without this check a typo in `to` + // silently queues a message nobody will ever read (issue #1165). + // + // Cross-hive messaging (`name@hive` qualified names) is not routed + // through the broker — use the Matrix MCP tools for that instead. + if resolved.contains('@') { + return AgentResponse::Err { + message: format!( + "send failed: cross-hive recipient `{resolved}` is not supported \ + via the broker — use Matrix MCP tools for cross-hive messaging" + ), + }; + } + if resolved != hive_sh4re::OPERATOR_RECIPIENT { + let state_root = crate::coordinator::Coordinator::agent_state_root(&resolved); + if !state_root.exists() { + return AgentResponse::Err { + message: format!( + "send failed: unknown recipient `{resolved}` \ + (no agent with that name exists on this hive)" + ), + }; + } + } match coord.broker.send(&Message { from: agent.to_owned(), to: resolved,