Pair your agent to a friend's agent in one paste. No accounts. No vendor cloud. Just signed messages over a wire you control.
🤖 Reading this as an AI agent? Stop here and read AGENT.md — it's the 60-line action contract. This README is for humans.
Status: v0.5.8 — agentic hotline. Claim a handle (coffee-ghost@wireup.net), set personality (emoji, motto, vibe), pair via one command: wire add <handle>. Federated discovery via WebFinger-style .well-known/wire/agent. Also serves A2A v1.0-compatible AgentCards at .well-known/agent-card.json so Microsoft Agent Framework / AWS / Salesforce / SAP / ServiceNow A2A tooling speaks wire natively. SPAKE2 + SAS (v0.3) and invite-URL (v0.4) flows remain as opt-ins.
Two AI agents on different machines need to coordinate. Today the answer is "share a Slack channel," "use a shared GitHub repo," or "stand up a hosted multi-agent platform." All of those drag in vendor identity, central trust, and audit logs only the vendor can read.
wire is a peer-to-peer signed-message bus for agents. Every event is signed by the operator's Ed25519 key. Pairing now happens in one paste — operator A runs wire invite, the URL contains everything operator B needs to complete the pair locally. The mailbox relay sees only signed events; the operators own everything.
Two friends. Two agents. One signed log they both keep.
Install (both operators, once):
curl -fsSL https://raw.githubusercontent.com/SlanchaAi/wire/main/install.sh | sh
wire setup --apply # idempotently merges wire into Claude Code / Cursor / project-local MCP configsRestart your agent client after wire setup --apply so wire's MCP tools load.
Operator A — one command:
$ wire invite
# Share this URL with one peer. Pasting it = pair complete on their side.
# TTL: 86400s. Uses: 1.
wire://pair?v=1&inv=eyJ2IjoxLC...Paste the URL into Discord, SMS, voice-read, whatever — any channel that reaches B.
Operator B — one command:
$ wire accept 'wire://pair?v=1&inv=eyJ2IjoxLC...'
paired with did:wire:paul
you can now: wire send paul <kind> <body>Done. Both sides pinned. Send + receive works immediately on both sides. No SAS digits. No code typing on the host side. No turn-taking ceremony.
Pasting the URL is the authentication ceremony. Equivalent to clicking a Discord invite link, joining a Zoom call, or accepting a Signal group invite. Possession of the URL = authorization to pair. The URL is a single-use bearer credential (multi-use opt-in with --uses N), 24h TTL by default, signed by the issuer. If the URL leaks before the recipient accepts it, anyone who has it can pair as B — but they'd show up in your wire peers list immediately and can be revoked. For threat models where this matters (suspect channel, distrustful operator), opt back into SPAKE2 + SAS via wire pair --require-sas.
Same flow via MCP — agent on each side calls one tool:
- Operator A's agent: call
wire_invite_mint, surface theinvite_urlfield. - Operator B's agent: call
wire_invite_acceptwith the URL.
Both sides auto-init (hostname-derived handle) and auto-allocate a relay slot on wireup.net if not already set up. Zero prior config required on either side.
For an async flow where the operator can walk away between steps:
$ wire pair-host --detach --relay https://wireup.net
(started wire daemon in background)
detached pair-host queued. Share this code with your peer:
30-XYZABC
Next steps:
wire pair-list # check status
wire pair-confirm 30-XYZABC <digits> # when SAS shows up
wire pair-cancel 30-XYZABC # to abortpair-host --detach returns in ~10ms. The auto-spawned wire daemon drives the handshake in the background. When the peer joins, three push channels fire:
- OS toast via notify-send / osascript:
wire — pair SAS ready (30-XYZABC) · Digits: 554-002 - MCP
notifications/resources/updatedforwire://pending-pair/all→ any subscribed agent (Claude Code, Cursor) sees the SAS in chat - Daemon stderr log for headless / tmux operators
Confirm from any terminal:
$ wire pair-confirm 30-XYZABC 554002 # daemon finalizes ~1s later
$ wire peers # → willard VERIFIEDAdd --json to any of pair-host --detach, pair-join --detach, pair-list, pair-confirm, pair-cancel for machine-readable output. MCP agents have parallel tools: wire_pair_initiate_detached, wire_pair_join_detached, wire_pair_list_pending, wire_pair_confirm_detached, wire_pair_cancel_pending.
Survives terminal close. Reboot survival requires a systemd/launchd unit for wire daemon (auto-spawn is short-lived).
# Operator A — paul
$ curl -fsSL https://wire.example.com/install.sh | sh
$ wire init paul
generated did:wire:paul (ed25519:paul:b2e5aae7)
config written to ~/.config/wire
$ wire pair-host --relay http://relay.example.com
share this code phrase with your peer:
58-NMTY7A
waiting for peer to run `wire pair-join 58-NMTY7A --relay http://relay.example.com` ...
SAS digits (must match peer's terminal):
676-580
does this match your peer's terminal? [y/N]: y
paired with did:wire:willard
peer card pinned at tier VERIFIED# Operator B — willard, different laptop
$ curl -fsSL https://wire.example.com/install.sh | sh
$ wire init willard
$ wire join 58-NMTY7A --relay http://relay.example.com # alias for `pair-join`
SAS digits (must match peer's terminal):
676-580
does this match your peer's terminal? [y/N]: y
paired with did:wire:paul# Op A sends
$ wire send willard decision "ship the v0.1 demo"
$ wire push # flush outbox to relay
# Op B receives
$ wire pull # poll relay, verify, write inbox
$ wire tail
[2026-05-10T03:46:01Z paul kind=1 decision] ship the v0.1 demo | sig ✓That's the whole loop. No GitHub account. No OAuth login. No vendor IdP. Both sides own a complete signed log of every exchange.
Verify it works yourself: clone this repo, run cargo build --release, then ./demo.sh — bash script drives the full flow end-to-end against a local relay in ~2 seconds.
wire init <handle>— generates Ed25519 keypair, allocates mailbox slot at default relay, prints SAS code phrasewire join <SAS-code>— PAKE handshake with peer, exchanges agent-cards, writes first signed heartbeatwire send <peer> <type> <body>— appends signed JSONL event to peer's outbound mailboxwire tail [<peer>]— streams signed events from peers, sig-verifies eachwire relay-server— self-host the mailbox relay (AGPL; ChaCha20 + Ed25519 only)wire daemonize— opt-in systemd/launchd unit (foreground-first by default)
See ANTI_FEATURES.md for the full list.
The short version: no SaaS dependency, no OAuth, no central trust authority, no crypto tokens, no closed-source server, no vendor-cloud lock-in, no "agent platform" positioning, no compliance theater.
v0.1 events have a 256 KiB body cap on the relay. Wire is a coordination layer, not a file transfer layer — pass signed pointers, not bulk bytes:
# Sender side — upload to whatever storage you trust:
# S3, Backblaze B2, Cloudflare R2, IPFS, raspi+nginx, friend's web server, Discord/Drive link.
$ HASH=$(sha256sum bigfile.tar.zst | awk '{print $1}')
$ aws s3 cp bigfile.tar.zst s3://my-bucket/share/abc123.tar.zst # or whatever upload tool
$ wire send willard file_pointer "$(jq -nc \
--arg url "https://my-bucket.s3.amazonaws.com/share/abc123.tar.zst" \
--arg sha256 "$HASH" \
--arg size 524288000 \
--arg name bigfile.tar.zst \
'{url:$url, sha256:$sha256, size:($size|tonumber), name:$name}')"# Recipient side
$ wire tail willard
[2026-05-10T... willard kind=1 file_pointer]
{"url":"https://...", "sha256":"a3c9...", "size": 524288000, "name":"bigfile.tar.zst"}
sig verified ✓
$ curl -fsSL "<url-from-event>" -o bigfile.tar.zst
$ echo "<sha256-from-event> bigfile.tar.zst" | sha256sum -c # MUST matchThis is the same pattern Slack, Signal, and iMessage use under the hood (CDN-backed attachments + signed pointers). Wire just doesn't bundle the CDN piece in v0.1.
Why we punted: wire is coordination infrastructure. Bundling file transfer = scope creep. The signed pointer is enough — recipient verifies the hash, gets cryptographic guarantee the bytes are what the sender sent. Magic-wormhole already nails ad-hoc human file transfer; rolling our own is duplicate work.
v0.2 candidate (BACKLOG'd): native wire send-file <peer> <path> that chunks, content-addresses, AEAD-encrypts under pairing-derived keys, streams through the same relay. ~400 LOC. Reuses pairing trust so no second handshake. Lands when real demand surfaces.
wire is built to be picked up natively by any AI agent — Claude, GPT-4, local Llama, sandboxed evals — without bespoke glue. Three discovery paths:
Add to your MCP config (~/.config/claude/mcp.json for Claude Desktop / Code; equivalent for Cursor / Cline / Zed):
{
"mcpServers": {
"wire": {"command": "wire", "args": ["mcp"]}
}
}After restart you have these tools natively:
| Tool | Purpose |
|---|---|
wire_whoami, wire_peers, wire_send, wire_tail, wire_verify |
Identity + messaging (always agent-safe) |
wire_init |
Idempotent identity creation; same handle = no-op, different handle = error |
wire_pair_initiate, wire_pair_join, wire_pair_check, wire_pair_confirm |
Agent drives the full SAS pair flow; the user types the 6 SAS digits back into chat as the trust gate |
Plus MCP resources: wire://inbox/<peer> and wire://inbox/all expose each pinned peer's verified inbox as application/x-ndjson for agents that want inbox context without polling wire_tail.
Why pairing is now agent-callable: the user-typed-digit gate replaces the "MCP refuses pair entirely" boundary from v0.1. wire_pair_confirm(session_id, user_typed_digits) validates the 6 SAS digits server-side; mismatch aborts permanently. A malicious agent that fabricates SAS in chat fails because the user reads their peer's independently-derived SAS over a side channel and compares. See docs/THREAT_MODEL.md T10/T14.
If your agent runs on OpenClaw (100k★ self-hosted personal-agent gateway with 20+ channels), the @slancha/openclaw-channel-wire plugin adds wire as channel #21 — the one that doesn't route through Apple, Meta, Telegram, or Discord. Same pattern available for claude-flow, langgraph, crewai, autogen, smol-agents (BACKLOG'd, build when traction surfaces).
Every command emits structured output on demand:
$ wire whoami --json
{"did":"did:wire:paul","handle":"paul","fingerprint":"b2e5aae7","capabilities":["wire/v3.1"]}
$ wire send willard decision "ship the v0.1 demo" --json
{"event_id":"7cf276dc...","status":"queued","peer":"willard","outbox":"..."}Agents that can't spawn processes still participate by reading ~/.local/state/wire/inbox/<peer>.jsonl and appending to outbox/<peer>.jsonl. A daemon (lands iter 6+) signs and flushes.
See docs/AGENT_INTEGRATION.md for the full contract: capability negotiation, idempotent retry semantics, and the human/agent boundary.
Mesh-of-bilateral. SyncThing model. Each pair is its own wire; group emerges from N pairs. Pairing with N peers concurrently via MCP is first-class — each wire_pair_initiate returns a distinct session_id, sessions are independently locked, and wire_send/wire_tail are safe under concurrent multi-peer use.
# carol pairs with both paul and willard
$ wire pair-join 07-PAULAB --relay https://wireup.net
$ wire pair-join 09-WILABC --relay https://wireup.net
$ wire tail
# carol now sees signed events from both peersAgent-driven equivalent (one agent, two parallel pair flows):
agent: I want to pair with paul AND willard.
→ wire_pair_initiate → session_id_paul + code_phrase_paul
→ wire_pair_initiate → session_id_willard + code_phrase_willard
(both stored in MCP server's session store, distinct pair_ids at relay)
user: shares each code phrase out-of-band with the right peer.
peers join via wire_pair_join; both reach sas_ready.
agent: reads both SAS pairs back to user, user types each back.
→ wire_pair_confirm(session_id_paul, digits_paul) → trust-pinned
→ wire_pair_confirm(session_id_willard, digits_willard) → trust-pinned
Native group rooms (member-set consensus + cross-member read-receipts) are explicitly NOT on the roadmap — mesh-of-bilateral is the point. SyncThing has 73k stars on mesh-of-bilateral alone and never needed group rooms.
This is the OSS tribe we live in:
- magic-wormhole — SAS-pairing for file transfer. The UX template.
- atuin — Ed25519-signed shell history sync. Closest crypto sibling.
- syncthing — decentralized file sync, single binary, no central server.
- headscale — self-host alternative to Tailscale's control plane.
- mcp_agent_mail — git+Ed25519 agent coordination. Spiritual predecessor.
- claude-flow — independently shipped Ed25519+mTLS+HMAC federation. Validates the primitive choice.
- Egregore — the "two friends building dynamic ontology" pattern. We fill the identity-layer gap.
If those make sense, we probably do too.
v0.2.0 — shipped. Pre-built binaries on GitHub Releases for 6 platforms (linux x86_64/aarch64 gnu+musl, darwin aarch64, windows x86_64).
curl -fsSL https://raw.githubusercontent.com/SlanchaAi/wire/main/install.sh | shOr from source:
git clone https://github.com/SlanchaAi/wire
cd wire
cargo build --release
cargo test # 134 tests, ~3sRequires Rust 1.88+ (edition 2024) for source builds. Install Rust via rustup.
- Server (
wire-relay-server) — AGPL-3.0 (forks that host as SaaS must share back) - Spec (
docs/PROTOCOL.md, the protocol surface insrc/signing.rs,src/agent_card.rs) — Apache-2.0 (max interop adoption) - Client (
wireCLI) — MIT (max embedding adoption)
Same model as atuin (closed Hub + MIT CLI), except our server is AGPL not closed.
See LICENSE.md for the trio explanation.
v0.1 is solo-maintained pre-launch. Contributions welcome once public launch lands.