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.
ask
ask(peer_name: str, query: str, reply_to: str | None = None, circle: str | None = None) -> strOpen a non-blocking ask thread. 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].
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) -> 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) -> 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.
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, command: str, circle: str = "default", message: str | None = None) -> strSpawn a new agent session in a project directory. The command must exactly match an entry in daemon.spawn.allowed_commands in ~/.repowire/config.yaml; spawn is off by default until you allowlist something.
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.