Control surfaces¶
The dashboard, Telegram bot, and Slack bot are peers too. They show up in list_peers alongside agents and use the same ask / notify_peer / broadcast primitives.
dashboard— Next.js UI atlocalhost:8377/dashboard, with a live mesh log and per-peer chat. See web dashboard.telegram— bot you talk to from your phone. Sticky routing:/select peersends subsequent messages as asks to that peer until/clear;/notifyand/fyiremain fire-and-forget. See Telegram bot.slack— Socket Mode bot. Same sticky-routing pattern with Block Kit peer pickers;notifyandfyiremain fire-and-forget. See Slack bot.
Human framing¶
Messages from @telegram, @slack, and @dashboard are humans. Agents that receive messages from these peers treat them as direct user instructions, not as agent-to-agent traffic. Telegram and Slack human inbound messages open tracked ask threads by default, so the recipient is reminded until it acks or replies. This framing is injected by repowire at delivery time — agents do not need to special-case the names themselves.
When an agent wants to reach the human, the move is notify_peer("telegram", "...") (or notify_peer("dashboard", ...), though the dashboard already sees turns and rarely needs an explicit notification). These peers have the human role, which bypasses circle filtering — they resolve and appear in list_peers mesh-wide regardless of the caller's circle.
What surfaces don't do¶
Control surfaces are clients of the routing API, not part of it. The daemon is the single source of truth for peer state and message routing. A surface that crashes does not lose mesh state; reopening it picks back up from the daemon.
Session-targeted controls¶
The first session-native control API targets durable repowire_session_id
bindings rather than display names:
POST /sessions/{repowire_session_id}/controls/notifyresolves the binding to its current active executor and sends through the existing notify delivery path. If no active executor is attached, it returnssession_executor_unavailableinstead of guessing from path or display name.POST /sessions/{repowire_session_id}/controls/resumereports the current resume capability for the binding. Active sessions returnstatus=active_executor; detached local-agent sessions with captured runtime ids returnstatus=resume_available. Passingdry_run=falsespawns the backend-native resume command through the daemon spawn service.
Session resume is not limited to peers originally spawned by Repowire. Spawn ownership is still required for destructive pane operations such as peer restart/kill, but session resume only needs a captured backend runtime session id and a backend that supports local resume.
These routes require the SQLite session binding store. Existing peer-targeted
ask, notify_peer, and dashboard routes remain compatible and continue to
route by peer identity.