io.github.gopalrajsuresh/covalent-bond
Peer-to-peer, end-to-end-encrypted collaboration channel for AI coding agents over MCP.
Open source Open in the app JSON README (API)
About
Peer-to-peer, end-to-end-encrypted collaboration channel for AI coding agents over MCP.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- gopalrajsuresh
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.1.2
- Open pull requests
- 3
- Last push
- 2026-09-03T11:28:26Z
- Repository state
- ativo
- Language
- JavaScript
- License
- MIT
- Added
- 2026-08-29 03:02:54
- Updated
- 2026-08-29 03:02:54
- Origin id
io.github.gopalrajsuresh/covalent-bond
README
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/banner-dark.png">
<img src="assets/banner.png" alt="Covalent Bond: two agents sharing an encrypted channel" width="100%">
</picture>
</p>
<h1 align="center">Covalent Bond</h1>
<p align="center">
<b>A secure channel that lets two AI coding agents on different machines work as one.</b>
</p>
<p align="center">
<a href="#quick-start">Quick start</a> ·
<a href="#how-it-works">How it works</a> ·
<a href="#tools">Tools</a> ·
<a href="#security">Security</a> ·
<a href="docs/ARCHITECTURE.md">Architecture</a> ·
<a href="CONTRIBUTING.md">Contributing</a>
</p>
<p align="center">
<img src="https://img.shields.io/badge/MCP-compatible-8A2BE2.svg" alt="MCP compatible">
<img src="https://img.shields.io/badge/Node.js-%E2%89%A518-brightgreen.svg" alt="Node.js >= 18">
<img src="https://img.shields.io/badge/E2EE-AES--256--GCM%20%2B%20X25519-1f6feb.svg" alt="E2EE: AES-256-GCM + X25519">
<img src="https://img.shields.io/badge/relay-Cloudflare%20Workers-f38020.svg" alt="Relay: Cloudflare Workers">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
</p>
---
A *covalent bond* is two atoms sharing a pair of electrons. Covalent Bond is two coding agents on different machines sharing something just as fundamental: a private, authenticated channel, and through it, a way of working.
Picture two developers pairing across a distance. One has their agent dialed in (organized skills, sharp conventions, the right context loaded) and it produces excellent work. The other is more ad-hoc, and their agent turns out something that's just *okay*. Covalent Bond is the channel that closes that gap: the well-tuned side can hand over the files, context, and conventions that make its agent good, so **both agents converge on the same high-quality way of working**. It bonds not just two agents, but two ways of working, pulling the weaker setup up to the level of the stronger, as equal peers.
It's peer-to-peer and end-to-end encrypted: the two agents pair up and exchange messages and files through a relay that **can never read the traffic**. It works with **any MCP-compatible agent** (Claude Code, Cursor, Codex, Windsurf, Cline, and others), exposing `bond_*` tools over the Model Context Protocol. And it keeps a human in the loop: every incoming file waits for explicit consent before it touches disk.
- 🤝 **Bonds two ways of working**: share files, context, and conventions so both agents level up together
- 🔒 **Authenticated E2EE**: a malicious relay can't read *or* MITM the channel
- 🌐 **Cross-machine**: pair agents anywhere, through a dumb relay (no inbound ports)
- 🙋 **Human-in-the-loop**: consent before any file is written; full audit log
- 🔌 **Agent-agnostic**: any MCP client, not tied to one vendor
> It doesn't magically clone one setup onto another. It's the secure, consent-gated channel that makes deliberately sharing your working style *possible* between two machines that otherwise can't reach each other.
## Quick start
**Shortcut: let your agent set everything up.** Paste [docs/AGENT-SETUP.md](docs/AGENT-SETUP.md) to any coding agent and say "set up Covalent Bond". It walks the agent through install, relay config, MCP registration, and pairing, with clear stops for the parts only a human may do.
Or do it yourself on **both machines** (steps 1–2), then pair (step 3).
1. **Register the MCP server** with your agent — no install needed, `npx` fetches [the npm package](https://www.npmjs.com/package/covalent-bond). For Claude Code:
```bash
claude mcp add --scope user --env COVALENT_RELAY_URL=https://covalent-bond-relay.gopalrajsuresh.workers.dev covalent -- npx -y covalent-bond
```
(`--scope user` makes the `bond_*` tools available in every project. The env var points at the public relay; to self-host instead, see [Pick a relay](#pick-a-relay).)
For other MCP clients (Cursor, Codex, Windsurf, …), this standard stdio-server config works in most of them; paste it into the client's MCP settings JSON (the top-level key is usually `mcpServers` or `servers`):
```json
{
"mcpServers": {
"covalent": {
"command": "npx",
"args": ["-y", "covalent-bond"],
"env": {
"COVALENT_RELAY_URL": "https://covalent-bond-relay.gopalrajsuresh.workers.dev"
}
}
}
}
```
<details>
<summary>Windows and local-testing notes</summary>
On **Windows**, if your client struggles to spawn `npx` directly, wrap it: `"command": "cmd", "args": ["/c", "npx", "-y", "covalent-bond"]`. For local testing without a deployed relay, run the mock relay from a source checkout (`npm run relay:dev`) and point `COVALENT_RELAY_URL` at `http://localhost:8787`.
</details>
<details>
<summary>Prefer running from source?</summary>
```bash
git clone https://github.com/gopalrajsuresh/covalent-bond.git covalent-bond
cd covalent-bond
npm install
npm test # optional but recommended; all suites run offline
cp .env.example .env # PowerShell: Copy-Item .env.example .env
```
The `.env` already contains the public relay URL. Then register with `command: node`, args `/absolute/path/to/covalent-bond/bin/cli.js` (Claude Code: `claude mcp add --scope user covalent -- node /absolute/path/to/covalent-bond/bin/cli.js`), no env var needed.
</details>
2. **Restart your agent session**, then verify: ask the agent to run `bond_status`. It should reply "No active session", which means the tools are live.
3. **Pair and share**
- Machine A: *"Create a Covalent Bond session"* → agent runs `bond_connect` → you get a code like `AbCd-1234-XyZw`.
- Tell the code to the other human **out-of-band** (chat or voice, never through the relay).
- Machine B: *"Join Covalent Bond session AbCd-1234-XyZw"* → agent runs `bond_join`.
- Either side: `bond_status` → **Secure channel established** → send files (`bond_send`) and messages (`bond_message`). Incoming files wait for the human to `bond_accept`.
- Done? `bond_end` on both sides.
## How it works
Both agents meet at a relay that is **untrusted by design** — it forwards ciphertext it can never decrypt. The session code travels human-to-human, never through the relay, and that out-of-band secret is what authenticates the channel:
```mermaid
sequenceDiagram
participant A as Agent A (host)
participant H as Humans (out-of-band)
participant R as Relay (untrusted)
participant B as Agent B (guest)
A->>A: bond_connect → session code
A-->>H: code shared by chat / voice
H-->>B: code entered on the other side
B->>B: bond_join(code)
A->>R: ephemeral public key (routing ID only)
B->>R: ephemeral public key (routing ID only)
Note over A,B: key = X25519 ⊕ session code → AES-256-GCM
A->>R: ciphertext
R->>B: ciphertext (relay sees nothing else)
B->>B: file held until human runs bond_accept
```
If anything in the middle tampers with the key exchange, key confirmation fails and the session aborts before any data flows — a malicious relay can't read *or* impersonate either side.
## Pick a relay
The relay is a dumb pipe and **untrusted by design**: it sees only a random routing ID and ciphertext, never the session code, keys, or plaintext, and a malicious relay still can't read or forge anything (that's covered by the test suite's MITM scenario). So either option below is equally secure; it's purely a convenience choice.
**Option 1: use the public relay (fastest)**
```
COVALENT_RELAY_URL=https://covalent-bond-relay.gopalrajsuresh.workers.dev
```
Sessions expire after 30 minutes of inactivity and nothing is retained. Best-effort availability, rate-limited.
<details>
<summary><b>Where to set <code>COVALENT_RELAY_URL</code></b> (either place works; a real environment variable wins over <code>.env</code>)</summary>
- **`.env` file (simplest)**: copy [`.env.example`](.env.example) to `.env` in the covalent-bond folder and edit the value. The MCP server reads it at startup, so it applies no matter which project you use the agent from.
- **MCP client config**: pass it when registering the server, e.g. for Claude Code:
```bash
claude mcp add --scope user --env COVALENT_RELAY_URL=https://... covalent -- node /absolute/path/to/covalent-bond/bin/cli.js
```
For other MCP clients, add it to the server's `env` block in their JSON config.
After changing either, restart your agent session so the MCP server relaunches.
</details>
**Option 2: deploy your own in ~2 minutes (free Cloudflare account)**
```bash
npm install -g wrangler
wrangler login # opens the browser; create a free account if you don't have one
cd cloudflare-worker
wrangler deploy # prints your relay URL: https://covalent-bond-relay.<your-subdomain>.workers.dev
```
Then set `COVALENT_RELAY_URL` to that URL on **both** machines. Full details (Durable Object migration, optional per-IP throttle, local `wrangler dev`) are in [cloudflare-worker/README.md](cloudflare-worker/README.md).
<details>
<summary><b>Or let your agent do it</b></summary>
Paste this to any coding agent running in this repo:
> Deploy my own Covalent Bond relay: install wrangler if missing, run `wrangler login` and wait for me to finish authenticating in the browser, then `wrangler deploy` from `cloudflare-worker/`, and tell me the URL to set as `COVALENT_RELAY_URL` on both machines. Follow `cloudflare-worker/README.md`.
The only manual step is the browser login; the agent handles the rest.
</details>
## Pair two agents
1. **Machine A**: *"Create a Covalent Bond session."* → the agent calls `bond_connect` and returns a code like `AbCd-1234-XyZw`.
2. **Share that code with Machine B out-of-band** (chat, voice, in person). It's the secret that secures the link. Never paste it into the relay.
3. **Machine B**: *"Join Covalent Bond session `AbCd-1234-XyZw`."* → the agent calls `bond_join`.
4. When `bond_status` shows **Secure channel established**, start sharing: *"Send `src/auth.js` to my peer,"* or hand over the pieces that make your agent good: a skill file, a conventions doc, the context that shapes how it works. The peer sees a consent prompt and accepts before anything is written, and the received content arrives wrapped as untrusted data for the other agent to read and adopt.
## Tools
- `bond_connect` — Create a session and get a shareable session code
- `bond_join` — Join a session using a code shared out-of-band
- `bond_status` — Connection status, pending transfers, and new events
- `bond_send` — Send a file to the connected peer, encrypted end to end
- `bond_message` — Send a short encrypted text message to the peer
- `bond_wait` — Long-poll for the next peer event
- `bond_accept` — Accept a pending file transfer after human consent
- `bond_decline` — Decline a pending file transfer
- `bond_end` — End the session and disconnect from the relay
Full reference:
| Tool | Parameters | What it does | Requires |
|------|------------|--------------|----------|
| `bond_connect` | — | Create a session as host; returns the code to share out-of-band | — |
| `bond_join` | `sessionCode` | Join a session with a code (`XXXX-XXXX-XXXX`, Base58) | — |
| `bond_status` | — | Handshake state, pending transfers, unread-event count, and events since the last call | — |
| `bond_send` | `filepath`, `message?` | Send a file (type whitelist, size cap, 10 s rate limit) with an optional context message | confirmed channel |
| `bond_message` | `content` | Send a short encrypted text message, max 4000 chars (agent-to-agent conversation) | confirmed channel |
| `bond_wait` | `timeoutSeconds?` | Long-poll for the next peer event (message, file, disconnect); default 50 s, max 300 s | confirmed channel |
| `bond_accept` | `transferId` | Write a pending file to `~/.covalent/incoming/` and return its content wrapped as untrusted data | human consent |
| `bond_decline` | `transferId` | Discard a pending transfer (the sender is not notified) | human consent |
| `bond_end` | — | Disconnect and clear session state, including pending transfers | — |
`?` marks an optional parameter. **confirmed channel** means the tool refuses to run until key confirmation has succeeded on both sides; **human consent** means the agent may only call it after the human explicitly decides on the pending transfer.
Incoming events raise a desktop notification (disable with
`COVALENT_NOTIFICATIONS=off`). File size defaults to 256 KB, overridable via
`COVALENT_MAX_FILE_KB` (up to 384 KB, bounded by the relay's wire limit).
## Security
Each session is secured by **two** secrets: ephemeral **X25519** keys exchanged through the relay, and a short **session code** the two humans share out-of-band. The code is mixed into the encryption key but **never sent to the relay**, so a relay that tampers with the key exchange (a MITM) can't derive the key, key confirmation fails, and the session aborts before any data flows. The relay only ever sees a routing ID, public keys, and AES-256-GCM ciphertext. Every incoming file waits for explicit human consent, and every operation is logged.
**Full details, threat model, and handshake diagram:** [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
> **Share the session code over a channel the relay operator doesn't control.** That out-of-band step is what makes the channel authenticated, not just encrypted.
## Testing
```bash
npm test # all suites, via test/run-all.js, against an in-process mock relay
```
No network or `wrangler` needed. The suite covers the key schedule, the full handshake and file transfer, two MCP servers end-to-end, a simulated malicious relay (`mitm`), and the relay's hardening. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#testing) for the breakdown, and [docs/TWO-MACHINE-TEST.md](docs/TWO-MACHINE-TEST.md) for a real two-machine run.
## Deploying the relay
The relay is a Cloudflare Worker in [`cloudflare-worker/`](cloudflare-worker/README.md) with one Durable Object per session. It stores only routing IDs, public keys, and ciphertext, expiring 30 minutes after the last activity. It can't decrypt anything.
## Status
Authenticated E2EE, MCP integration wired end-to-end, full test suite green. Pre-1.0: the protocol and API may still change.
## Contributing & security reports
Contributions are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md), which includes the security invariants and the branch/PR workflow. To report a vulnerability, please use the private process in [SECURITY.md](SECURITY.md), not a public issue.
## License
MIT; see [LICENSE](LICENSE).
---
<p align="center">
<sub>Two machines. One way of working. <a href="#covalent-bond">Back to top ↑</a></sub>
</p>