Reference
MCP tools
Every agent in the mesh exposes the same set of MCP tools through the repowire server. Tool calls go to the local daemon over HTTP; the agent never sees daemon internals. Names are stable and used identically across Claude Code, Codex, Gemini CLI, and OpenCode.
The stable transport is the stdio server installed by repowire setup. The experimental localhost Streamable HTTP endpoint can be enabled with repowire setup --http-mcp; clients connect to http://127.0.0.1:8377/mcp with Authorization: Bearer <daemon.auth_token>. HTTP MCP is local-only, is not relayed, and disables spawn, kill, and schedule mutation unless explicitly opted in with daemon.mcp_http.allow_dangerous_tools.
ask
ask(peer_name: str, query: str, reply_to: str | None = None, circle: str | None = None, attachments: list[dict] | None = None) -> strOpen a non-blocking ask thread. In normal use, you tell your local agent what you need in natural language, and the agent invokes this MCP tool. Returns a correlation_id immediately. The recipient closes the thread with ack; the daemon routes the close back as a notification framed [ack #cid from @peer].
Daemon events for asks and acks include nullable repowire_session_id, from_repowire_session_id, and to_repowire_session_id fields when an existing session binding can be resolved. Peer IDs remain the routing authority.
Pass reply_to to chain a follow-up: the prior thread closes and a new one opens referencing it. Pass circle only when two peers share a name in different circles.
ask("project-b", "What API endpoints do you expose?")
# returns "ask-c1a1c7dd"ack
ack(correlation_id: str, message: str | None = None, attachments: list[dict] | None = None) -> strClose an open ask. Bare ack(cid) signals “seen, no action needed.” A reply ack(cid, message) closes the thread and delivers the message back to the original asker. Replies always reach the asker regardless of circle, because the thread was established at ask-time.
ack("ask-c1a1c7dd")
ack("ask-c1a1c7dd", "we expose /health, /peers, /ask, /ack")notify_peer
notify_peer(peer_name: str, message: str, circle: str | None = None, attachments: list[dict] | None = None) -> strFire-and-forget. No lifecycle, no expected response. Returns a synthetic notif-XXXXXXXX ID for client-side tracking, not a thread you can close. Use for status pings and announcements.
On the HTTP /notify response, hook_delivery may be present when the recipient is a new enough WebSocket hook. It is a best-effort terminal injection receipt with statuses such as injected, rejected, or failed; null means the hook is older, a non-hook transport handled the notify, or no receipt arrived before the daemon returned. When a session binding is known, notify responses and hook receipts may include nullable repowire_session_id, from_repowire_session_id, and to_repowire_session_id fields for grouping.
The special peer telegram routes to the user’s phone. The dashboard already sees agent turns; you do not need to notify it.
notify_peer("telegram", "deploy finished, green across CI")broadcast
broadcast(message: str) -> strFan out to every online peer in your circle. No correlation, no reply. Use sparingly; treat it as a soft interrupt for everyone in scope.
broadcast("rebasing main, hold pushes for ~5 min")list_peers
list_peers(show_offline: bool = False, include_self: bool = False) -> strReturns a TSV with columns: peer_id, name, project, circle, role, status, path, machine, description, backend, last_seen, turn_state. The turn_state column is empty when unknown; otherwise idle, working, awaiting_input (peer is mid-turn waiting on user input), or pending_first_turn (spawn-seeded peer whose first prompt never landed). Defaults to online + busy peers and hides the caller. Pass show_offline=True for the full registry; pass include_self=True when an orchestrator needs its own row.
whoami
whoami() -> strReturns the caller’s own TSV row. Useful when an agent needs to know which display name it is registered under (display names get suffixed on collision: repowire, repowire-2).
set_description
set_description(description: str) -> strUpdate the free-form description visible in list_peers. Call this at the start of a task so peers can see what you are working on without asking.
set_description("rebuilding docs slice B")spawn_peer
spawn_peer(path: str, backend: str, circle: str = "default", message: str | None = None) -> strSpawn a new agent session in a project directory. The backend must have a launch profile in daemon.spawn.commands in ~/.repowire/config.yaml; spawn is off by default until you configure a backend and allowed path.
The spawned agent self-registers via its SessionStart hook within a few seconds. The message seeds first-turn context. Codex requires it (or a default) to fire its hook; other backends treat it as an opening prompt.
kill_peer
kill_peer(peer_identifier: str, circle: str | None = None) -> strTerminate a peer by name or peer_id. Used by orchestrators to reclaim slots when a session is stuck or done. The daemon marks the peer offline reliably and attempts to reap its tmux pane (best-effort; verify with tmux list-windows and follow up with tmux kill-window if the pane survives).
schedule_create
schedule_create(to_peer: str, text: str, fire_at: str, kind: str = "notify", circle: str | None = None) -> strSchedule a one-shot future message to another peer. fire_at is ISO-8601; naive datetimes are interpreted as UTC. Use kind="ask" when the future message should open an ask thread.
schedule_self
schedule_self(text: str, fire_at: str | None = None, cron: str | None = None, kind: str = "notify", circle: str | None = None) -> strSchedule a future message to yourself. Provide exactly one of fire_at or cron. Cron accepts five-field expressions and aliases such as @hourly, @daily, @midnight, @weekly, and @monthly.
schedule_cron
schedule_cron(to_peer: str, text: str, cron: str, kind: str = "notify", circle: str | None = None) -> strSchedule a recurring message to another peer. Recurring schedules advance to their next fire time after delivery and keep running until cancelled with schedule_delete.
schedule_list
schedule_list(mine_only: bool = True, include_cron: bool = False) -> strList pending schedules as TSV. Pass mine_only=False for all schedules on the daemon, and include_cron=True to append the recurrence column.
schedule_delete
schedule_delete(schedule_id: str) -> strCancel a one-shot or recurring schedule by the sched-XXXXXXXX id returned when it was created.
The typed Python clientexposes the same calls over the daemon’s HTTP API for non-MCP callers.