Architecture¶
Repowire is a local-first routing daemon plus thin transport adapters for each agent runtime.
Agent runtime
├─ hooks + MCP (Claude Code, Codex, Gemini)
├─ plugin + WebSocket (OpenCode)
├─ extension (Pi)
└─ channel / ACP transport (Claude Code experimental)
↓
HTTP/WebSocket daemon on 127.0.0.1:8377
↓
Dashboard, Telegram, Slack, orchestrator peers, relay, and other peers
The daemon is the single routing hub. It does not care whether a peer arrived through hooks, an OpenCode plugin, the Pi extension path, a bot, relay traffic, or experimental channel/ACP delivery. Every peer is represented in the registry and routes messages through the same core message layer.
Core modules¶
| Area | Files | Responsibility |
|---|---|---|
| Agent backends | repowire/agent_types.py, repowire/agent_backends.py |
Serialized backend identity plus setup, spawn, resume, MCP config, and post-spawn behavior dispatch |
| Daemon app | repowire/daemon/app.py, repowire/daemon/deps.py |
FastAPI app factory, dependency wiring, dashboard/static serving |
| Peer state | repowire/daemon/peer_registry.py |
Registration, liveness, circles, roles, lazy repair |
| Message routing | repowire/daemon/peer_delivery.py, repowire/daemon/transport_router.py, repowire/daemon/message_router.py, repowire/daemon/websocket_transport.py |
Delivery orchestration, ACP-before-WebSocket transport selection, and wire delivery over connected peers |
| Ask lifecycle | repowire/daemon/ask_tracker.py, repowire/daemon/routes/asks.py |
Open ask state, pending reminders, close/ack handling |
| Session controls | repowire/daemon/session_controls.py, repowire/daemon/routes/sessions.py |
Session-binding resolution and session-targeted control capability routes |
| Session acquisition | repowire/daemon/session_control.py, repowire/daemon/state/operations.py |
Durable operation records and live-executor acquisition for session/job work |
| Schedules | repowire/daemon/scheduler.py, repowire/daemon/schedule_store.py, repowire/daemon/routes/schedules.py |
One-shot and recurring cron deliveries |
| Jobs | repowire/daemon/job_runner.py, repowire/daemon/state/work.py, repowire/daemon/state/calendar.py, repowire/daemon/routes/work.py |
Durable tracked work, recurring calendar templates, and spawned job dispatch |
| Hooks | repowire/hooks/ |
Runtime event adapters, tmux injection, transcript/chat extraction |
| MCP server | repowire/mcp/server.py |
Agent-facing tools over stdio |
| Control surfaces | web/, repowire/telegram/bot.py, repowire/slack/bot.py |
Dashboard and human/service peers |
| Relay | repowire/relay/server.py, repowire/daemon/relay_client.py |
Hosted remote dashboard and cross-machine tunnel |
Transports¶
Hooks + MCP¶
Claude Code, Codex, and Gemini use lifecycle hooks for registration/status/chat extraction and MCP tools for outbound commands. The hook adapter normalizes each runtime's event names and response fields.
Default message delivery still uses tmux injection plus Stop-hook reminders for unacked asks. The MCP server lazily registers on tool calls so runtimes that initialize late, especially Codex, still get a peer identity before routing.
If a hook-backed orchestrator reconnects after daemon restart or WebSocket churn without carrying its prior peer_id, the daemon may reclaim the existing offline identity when the role, display name, circle, backend, and path match unambiguously. Queued notifications for that peer are replayed over the renewed WebSocket before falling back to Stop-hook or CLI draining.
OpenCode plugin and Pi extension¶
OpenCode does not expose the same hook shape, so Repowire installs a TypeScript plugin. The plugin holds a WebSocket connection to the daemon and bridges OpenCode session events into the same peer/message model. Pi uses Repowire's extension path when setup detects the pi CLI or config.
Channel / ACP transport¶
repowire setup --experimental-channels installs Claude Code's experimental channel/ACP transport. Messages arrive as <channel source="repowire"> tags, while legacy query replies route through a channel reply tool. The normal repowire mcp server remains installed for stable tools such as ask, ack, notify_peer, schedules, and peer listing. This requires Claude Code support, claude.ai login, and bun. Treat this path as experimental; hooks + MCP remain the default.
Relay¶
The daemon connects outbound to the hosted relay over WSS. The relay tunnels dashboard HTTP/SSE calls and bridges WebSocket traffic without requiring inbound access to the user's machine.
Lazy repair¶
Repowire avoids polling loops. Liveness repair, persistence flushes, and ghost cleanup are piggy-backed on user-visible requests, bounded by cooldowns. The design rule is: repair when needed, not on timers.
When lazy repair detects a self-inconsistent peer (e.g. online but no live WebSocket, a missing pane, or a dead agent pid) it emits a peer_contradiction event once per transition, so silent failures surface in the dashboard stream. repowire peer doctor <peer> is the explicit, operator-triggered counterpart: it runs the same reconciliation, then reports identity, inbound reachability, pending asks, and contradictions on demand. repowire peer rehook <peer> is the non-destructive recovery (re-establish the inbound ws-hook without killing the pane). A delivery trace ledger (repowire trace <id>) records per-message ask/notify stages for post-hoc "where did it go" inspection, persisted in a dedicated SQLite table rather than the bounded dashboard event buffer.
v0.14 session-native direction¶
The current stable surface is peer-oriented, but the v0.14 architecture train is moving toward a session-first mesh:
- Sessions become the durable unit of work.
- Peers remain runtime executors.
- Ask/notify delivery now goes through a delivery service plus transport router; WebSocket hooks, experimental ACP, relay, and future transports continue moving toward transport-neutral routing.
- The dashboard currently shows a selected peer/session timeline, merging Claude transcript history where available with realtime events.
- The first session-targeted control routes resolve
repowire_session_idbindings to an active executor or explicit resume capability status. - Broader composer actions, scheduling, approval handling, and backend/model controls move toward the same shared session command surface.
This is a roadmap. Current routes and tools still expose peers, circles, asks, notifications, and schedules. The ask/notify delivery-service and transport-router extraction has landed, but ACP remains experimental and not every route/control path is transport-neutral yet.
Knowledge graph¶
graphify-out/GRAPH_REPORT.md summarizes the codebase graph. The current report identifies the main hubs as AgentType, Config, PeerRegistry, MessageRouter, and WebSocketTransport, with communities around daemon routing, CLI/setup, channel installer, Telegram, attachments, hook normalization, relay auth, and peer lifecycle.
Keep generated graph JSON and cache files out of prose docs. Link or summarize the report when useful; do not paste large graph artifacts into README or hand-written docs.