AgentBridge
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@AgentBridgeask sam's agent which config file the staging API reads at boot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
AgentBridge
Ask another person's coding agent a question — across different machines, networks and subscriptions — without waiting for that person to become available, and without either of you running a server.
Language note: the code, comments and this README are in English. Everything the tool says to a human — CLI output, errors, the agent-facing channel notices — is in Spanish, and so is the documentation for the people actually running it. That was a deliberate product choice, not an oversight.
¿Español? La guía paso a paso para las dos personas que lo van a usar está en
docs/inicio-rapido.md.
The problem
You're deep in a task and you need one fact that lives in someone else's head — or, more often, in someone else's repo, which their agent already knows. So you message them. They read it an hour later, ask their Claude Code, copy the answer back, and you've lost the afternoon.
The bottleneck isn't the answer. It's the human in the middle relaying it.
AgentBridge lets your agent ask their agent directly, with the other person's explicit, revocable permission, inside a folder they control.
Related MCP server: Covalent Bond
How it works
flowchart LR
A["Your Claude Code<br/>(ask_contact)"] -->|sealed wrap| B1["Public Nostr boards<br/>(five, by default)"]
B1 -->|sealed wrap| C["Their Claude Code<br/>locked-down session"]
C -->|sealed wrap| B1
B1 -->|answer| AEach person runs
setuponce: it creates a key on their own machine and writes their profile. There is no account and no server of ours.They exchange links (
agentbridge:nprofile1…). One asks for permission withconnect; the other sees it withrequestsand decides withapproveorreject. Permission is directional, and only whoever granted it can take it back, at any time, withrevoke.Questions and answers travel as NIP-59 sealed wraps through public Nostr boards. A board sees an encrypted envelope, the ephemeral key that published it, the recipient's key it is addressed to, its size and its timing. It never sees the content, and it never sees who wrote it — but a board operator can watch which key receives envelopes, and correlate sizes and timing across boards.
The responder's agent runs in a dedicated, permission-restricted Claude Code session that can read what its owner chose — one folder by default — and nothing else, and answers with a single
replytool.The answer comes back through
check_answerorticket. Nobody had to be online at the same moment; a question is retried for up to seven days.
Security model — read this before you install it
The responder's session runs unattended, and an incoming question is untrusted input written by someone else. The design assumes that and is built around one rule:
A concrete rule holds. A prose rule does not.
Adversarial testing on this project showed a persona instruction ("don't read anything outside this folder") gets applied at answer time and can be talked around, while a deny rule or a path fence holds. So the boundary is enforced by configuration, not by asking the model nicely.
What the responder session cannot do, in every permission mode:
Run shell commands, edit or write files, fetch the web, or spawn subagents — all denied.
Read anything outside the folders its owner chose. Enforced by
permissions.blockReadsOutsideWorkingDirectories, which must be nested insidepermissions; a copy at the top level of the settings file is accepted and silently ignored. The wider scopes below add directories topermissions.additionalDirectories; they never turn the fence off.
What it can do — the part you must accept:
Everything it can read is readable by anyone allowed to ask you. In the shared folder that includes a key file, an
id_rsaor a password written in a document; only files named.envor.env.*are denied there in every scope. The correct mental model is: that folder is public to anyone allowed to ask you. Curate it deliberately. Do not point it at a working repo.Project configuration that lands in that folder later —
.claude/settings.jsonhooks,.mcp.json,.claude/agents,.claude/skills,.claude/commands,CLAUDE.local.md— takes effect at the next session start. Thedoctorcommand flags all of them, and anAGENTS.mdtoo: Claude Code 2.1.282 does not read it at all, but a later version might. Nothing prevents a sync client or agit pullfrom placing them.
What the responder can see: three scopes
setup asks the answerer once, for every contact at once (there is no per-contact scope):
Scope | Readable | Denied on top of the fence |
1 — one folder (default, recommended) | the shared folder |
|
2 — several folders | the shared folder plus the folders the answerer names | the caja fuerte; |
3 — the whole personal folder | the shared folder plus the home directory | the caja fuerte |
The caja fuerte ("safe") is a fixed list in code (CAJA_FUERTE_HOME in
packages/cli/src/commands/setup-responder.ts) that nobody, the answerer included, can open
through setup: the
AgentBridge identity folder and the dedicated profile wherever they live, the owner's everyday
Claude (~/.claude, ~/.claude.json*, the desktop app's configuration), the best-known credential
stores (~/.ssh, ~/.gnupg, ~/.aws, ~/.azure, ~/.config/gcloud, ~/.kube, ~/.docker,
~/.config/gh, ~/.npmrc, ~/.pypirc, ~/.netrc, ~/.git-credentials, cargo credentials,
~/.terraform.d, ~/.config/op), shell and REPL histories, the macOS keychain and browser
profiles, their Linux equivalents, all of ~/AppData on Windows, and every .env, .env.*,
*.pem, *.key, *.p12 and *.pfx under the home. It closes the best-known places, not every
secret a person has: a password written in a document, mail and chats saved on disk, or a key
file with an unusual name stay readable in scope 3. It also covers only the usual locations: an
everyday Claude run with a custom CLAUDE_CONFIG_DIR, or a dedicated profile left over from an
older --profile, is not in the list.
Scope 3 needs a typed CONFIRMAR after a screen that says, plainly, that anyone the answerer
approves can then ask about any file in their personal folder outside the caja fuerte. On
Windows only scope 1 exists for now. Scope 2 needs each extra folder's absolute path in a rule,
and how Claude Code anchors a drive-letter path is unverified. Scope 3 rests on the ~/… rules,
which have never been checked on Windows, and its consent screen tells the person the caja fuerte
stays closed: a promise nobody has checked is not made at the moment they type CONFIRMAR. Running
section 8 of the acceptance runbook on a Windows machine is what would lift this.
Every rule that must hold outside the working directory is anchored — ~/… for the home,
//<absolute path>/… per extra folder. That is the one fact this design rests on: on Claude Code
2.1.282, with the home added as a readable directory, an unanchored Read(**/.env) did not stop a
direct read of ~/proj/.env; Read(~/**/.env) did. The same binary also showed that Grep and Glob
respect these denies, including when they recurse from an allowed ancestor; that case variants and
symlinked spellings of a denied path are refused too; and that nothing from an extra folder's own
configuration (CLAUDE.md, .claude/, .mcp.json, CLAUDE.local.md, AGENTS.md) reaches the
model. Those are behaviours of one Claude Code version, so the acceptance runbook re-checks them
against the installed one.
The scope is stored in responder.json (version 2; a 0.3 version-1 file reads as scope 1). setup
rewrites the profile's settings.json from it on every run, and writes .agentbridge-scope.md into
the shared folder so the model knows its reach — the persona CLAUDE.md imports it. responder
refuses to start, and doctor fails, when settings.json does not match the saved scope exactly:
a missing caja fuerte rule, or a readable directory nobody chose.
npx -y @joseamica/agentbridge@latest doctor is how you verify all of this on a real install,
including that every board you use actually accepts and returns what you publish. Run it before
you trust it.
Privacy: what's guaranteed and what isn't
Guaranteed:
Nobody outside the two of you can read questions, answers, names or notes.
The public event never names the sender: anyone watching a board sees "an envelope for key X", signed by a single-use key that is thrown away right after.
Nobody can impersonate a contact: every message is only accepted if the seal is signed by the expected key.
Not guaranteed:
Hiding who talks to whom from a board's operator. A board can correlate the IP that publishes an envelope for X with the IP that later reads X's envelopes, and — where it requires NIP-42 AUTH — the actual key doing the reading. Copying the same envelope to several boards lets an operator correlate across boards too.
Forward secrecy. If your key is ever stolen, whoever holds it can decrypt any envelope addressed to you that a board kept.
Deletion. The NIP-40 expiration tag asks boards to delete after 7 days; it does not force them to.
Availability under a targeted attack. Rate limits contain casual abuse; an attacker with real resources can degrade service for one specific key, including crowding out legitimate questions.
Protecting the key from other programs you run. The 0600 permission on
identity.jsonkeeps other users of the machine out, not other programs of yours. The locked-down responder session cannot read it — in scope 1 because it lies outside the fence, in scopes 2 and 3 because its folder is denied by name — but an ordinary Claude Code session on the same machine could.
And the one that matters most in practice: everything the responder can read is readable by anyone you've given permission to ask you. In the shared folder that includes a stray key file; in scope 3 it is every file in your personal folder outside the caja fuerte. Say it out loud to the other person before either of you puts anything in there.
Requirements
Node.js >= 22.13
Claude Code on the responder's machine (developed against 2.1.270; the permission behaviours the 0.4 scopes rest on were verified on 2.1.282)
There is nothing to deploy, host or pay for. Both machines only ever talk out to public Nostr boards; neither is exposed to the internet, and there's no server of ours in the middle.
Two people, two roles
Role | Who it is | What they do |
Answerer | the person whose knowledge you want | Leaves a Claude Code session running in a locked room, with copies of only the files they chose to share. |
Asker | the person with the question | Asks from their own Claude Code, or from the CLI. |
Permission is directional. Ana being allowed to ask Dev does not let Dev ask Ana. If you want
both directions, do the grant step twice, once each way. revoke is also directional: only the
person who granted permission (the answerer) can take it back instantly with revoke <name>. The
asker simply stops asking — there's no revoke for that side.
The "locked room" is the important idea. The answerer picks one folder and copies into it only what they're willing to share. By default their agent can read that folder and nothing else on the machine — that's enforced by configuration, not by asking the model nicely. Everything in the room is fair game, so the room is curated on purpose. It is not your working repo. The answerer can widen the room to more folders or to their whole personal folder minus the caja fuerte — see What the responder can see.
sequenceDiagram
participant A as Ana's Claude Code
participant B as Public Nostr boards
participant D as Dev's locked session
Note over A,D: one time: both run setup, Dev approves Ana's connect request
A->>B: sealed wrap: ask_contact "which timeout applies to card reads?"
B->>D: Dev's channel picks it up
Note over D: reads only the shared folder
D->>B: sealed wrap: reply
B->>A: check_answer returns the answerNobody has to be online at the same moment. If Dev's session is down, the question waits — on the boards, retried automatically — until he starts it again.
Quickstart
The guided way (recommended)
On each machine, run one command and answer its questions — in Spanish, like everything else a human sees in this tool:
npx -y @joseamica/agentbridge@latest setupIt creates your key and profile if they don't exist yet, asks whether you're going to answer
questions, ask questions, or both, and — before it ever asks you to name a folder to share —
explains in plain language what putting one there means: everything inside becomes readable by
anyone you let ask you, including a stray .env or key file.
Three folders it refuses outright, with no confirmation available: your own home directory; any
folder containing your AgentBridge identity or the dedicated responder profile; and a path that
is not a directory at all (a file, a broken symlink, or something it could not inspect). Seven
more it will use only after you type CONFIRMAR, and it names which one fired: a .git
repository inside, credential-shaped filenames, symlinks it did not follow, a node_modules it
did not read, project configuration already sitting there (.claude/settings*.json, .mcp.json,
AGENTS.md, CLAUDE.local.md, .claude/agents|skills|commands), a tree too deeply nested to
walk fully, and a tree too large to walk fully — the last two because it cannot then promise none
of the others is hiding further in. It never creates that folder silently.
Next it asks what the answering agent can see — the shared folder only, that folder plus others the
answerer names one by one, or the whole personal folder minus the caja fuerte, behind a typed
CONFIRMAR (on Windows, only the first for now). Each extra folder goes through the same checks,
less two that are not true of it: project configuration, which does not load from an additional
directory, and symlinks, whose real target Claude Code holds to the same fence and caja fuerte.
Enter keeps what the machine already has.
Then it performs the rest instead of printing it. It opens Claude's login in the dedicated
profile — the browser opens, you type your password, you come back — and afterwards checks for
itself whether a session actually exists. It copies your link to the clipboard. It registers the
MCP server if you say yes. It runs every doctor check and speaks up only about the ones that
need you to do something, not the full diagnostic. It ends with a short verdict — what's ready, what's still
pending — and then, if nothing is blocking, offers to start answering right there: say yes and that
terminal becomes the responder.
setup is a thin conductor: every step it takes is one of the commands documented below
(connect, setup-responder, doctor, responder, claude mcp add, claude auth login) — it
never reimplements their logic. If it can't run interactively (no TTY — a script, CI, a redirected
pipe), it says so immediately and prints the equivalent commands instead of hanging.
Nothing it prints is a line you have to paste to finish installing, on any platform, and
tests/acceptance/docs.test.ts holds these docs to the same rule. The first real Windows install
of 0.2 ended in seven pending items, two of which were bash — an inline environment-variable
assignment in front of claude, and a path to a shell script — on a machine where neither could
run.
Read on if you want to understand exactly what each step does, run one by hand, automate it, or
fix something doctor flagged.
On both machines
Node >= 22.13 is required, to run npx — nothing else. The responder also needs Claude Code; the
asker only needs it if they want to ask from inside their agent rather than from the terminal.
Nothing to clone, build, or alias. Every command below runs through npx, which fetches
AgentBridge the first time it's used and reuses it after that:
npx -y @joseamica/agentbridge@latest --help(Hacking on AgentBridge itself instead of installing it? See Running the CLI from a local clone below.)
Manual, step by step
Ana is going to ask; Dev is going to answer. Swap the names for your own.
On both machines — create an identity and see your own link:
npx -y @joseamica/agentbridge@latest setup
npx -y @joseamica/agentbridge@latest linkThis is local: ~/.agentbridge (or $AGENTBRIDGE_HOME) holds your key and your database, and
nothing you do here talks to anyone else yet.
On Dev's machine — build the shared folder and the locked session:
npx -y @joseamica/agentbridge@latest setup-responder --share <a folder Dev is willing to share>This creates the shared folder if it isn't there, creates a dedicated Claude Code profile at
~/.agentbridge-responder (override with --profile), writes the restricted permissions, writes
a responder.json recording the folder, the model and the effort, installs the plugin into that
profile, and drops a persona CLAUDE.md and .agentbridge-scope.md into the shared folder. It
refuses to run if that profile — or Dev's identity folder — would land inside the shared folder.
setup-responder always writes scope 1, and rewrites settings.json and responder.json every time:
run by hand on a profile that had a wider scope, it narrows it back to one folder. The wider scopes
are chosen only through setup. Copy into that folder
only what Dev is willing to share: not the working repo, nothing with credentials.
Logging that dedicated profile in is a browser and a password, so it is setup's job, not a line
to paste — see the guided way above. Once there is a session, this is how Dev starts answering:
npx -y @joseamica/agentbridge@latest responderIt reads responder.json from the dedicated profile, sets that profile's CLAUDE_CONFIG_DIR
itself, and hands the terminal to Claude Code with the shared folder as its working directory.
The first time, it'll ask whether to trust the development channel — that's the AgentBridge plugin
setup-responder just installed; accept it. It takes over this terminal until Ctrl+C, so keep it
running there, or under tmux, and open a new terminal window for the next command. Pass the
same --profile you gave setup-responder if it wasn't the default.
npx -y @joseamica/agentbridge@latest doctor --profile ~/.agentbridge-responder --share <the shared folder>Every line should read [ok]. This is the step that tells you the fence is real, the plugin is
installed, and nothing dangerous landed in the shared folder — including that every board Dev
uses actually accepts and returns what's published to it, not just that the socket opens. Run it
before you trust the setup.
On Ana's machine — ask for permission and ask:
npx -y @joseamica/agentbridge@latest connect "<Dev's link>" --note "soy Ana"The first step here takes a few seconds — it's mining proof of work, on purpose, as an antispam
measure. Dev sees the request with requests and grants it with approve <id>; both sides can
then confirm the same state with contacts.
npx -y @joseamica/agentbridge@latest ask dev "which timeout applies to card reads?" --wait 120Or — the actual point of this thing — from inside her own Claude Code:
claude mcp add agentbridge --scope user -- npx -y @joseamica/agentbridge@latest mcpRestart any session that was already open, then just tell her agent to ask Dev. It gets
list_contacts, ask_contact, check_answer and connect. check_answer long-polls for at
most 45 seconds per call, so it never hangs a tool call.
After that
Dev keeps his session running and forgets about it. Ana asks whenever she needs to. Neither of them has to interrupt the other. If Dev's session is off, the question waits — retried automatically for up to a week — and lands the moment he starts it again.
For the full pilot protocol in Spanish — including the security checklist you should run before
trusting this with anything real — see
docs/runbooks/aceptacion-0.4.md. There is also a friendlier
Spanish quickstart at docs/inicio-rapido.md.
CLI reference
Every command below is shown as npx -y @joseamica/agentbridge@latest <command>, the same form
used throughout this README. If you installed the package globally, drop the npx -y @joseamica/agentbridge@latest prefix and run agentbridge <command> instead.
Guided:
npx -y @joseamica/agentbridge@latest setup [--repo <dir>] [--profile <dir>] [--relays <url,url,…>]
(interactive, in Spanish — creates your key and profile, then runs
everything below for the role(s) you pick: the login, the shared
folder, the checks, the MCP registration, and the responder itself)
(--relays alone rewrites your board list and exits; it asks nothing)
Your link and your permissions:
npx -y @joseamica/agentbridge@latest link (prints your own agentbridge:nprofile1… link)
npx -y @joseamica/agentbridge@latest connect <link> [--note "who you are"]
npx -y @joseamica/agentbridge@latest contacts (who you can ask, and who can ask you)
npx -y @joseamica/agentbridge@latest whoami
Requests that reach you:
npx -y @joseamica/agentbridge@latest requests
npx -y @joseamica/agentbridge@latest approve <id>
npx -y @joseamica/agentbridge@latest reject <id>
npx -y @joseamica/agentbridge@latest revoke <name>
Asking:
npx -y @joseamica/agentbridge@latest ask <name> <question…> [--wait <seconds>|--no-wait]
npx -y @joseamica/agentbridge@latest ticket <id> [--wait <seconds>]
npx -y @joseamica/agentbridge@latest mcp (MCP server for Claude Code or Codex)
Answering from this machine:
npx -y @joseamica/agentbridge@latest responder [--profile <dir>]
(start answering — reads responder.json from the dedicated profile
and hands the terminal to Claude Code until Ctrl+C)
npx -y @joseamica/agentbridge@latest setup-responder --share <dir> [--profile <dir>] [--repo <dir>] [--model sonnet] [--effort low]
npx -y @joseamica/agentbridge@latest doctor [--home <dir>] [--profile <dir>] [--share <dir>] [--repo <dir>]
Environment: AGENTBRIDGE_HOME (the folder with your identity and your database)Exit codes: 0 success, 1 expected failure, 2 unexpected.
Architecture
Path | What it is |
| Identity, the NIP-59 envelope pipeline (seal, gift wrap, proof of work), the local SQLite store (contacts, questions, cursors), and the board pool client. No server of ours anywhere in here. |
| The Claude Code plugin: the responder's dispatcher (turn coordination that used to live in the relay), inbound question handling, and the MCP server exposing |
| Every command above, plus the asker-side MCP server ( |
| Plugin manifests and the built bundle the responder's dedicated Claude Code profile loads. |
|
|
Correlation's safety does not come from hiding an identifier from the model — the channel tells the
model the short code and asks it to copy it back exactly. What actually protects it: at most one
question is ever active at a time, and reply's code is checked for an exact match against that
one active question — a wrong or missing code fails the reply outright instead of ever landing on
the wrong question.
Development
npm ci
npm test # needs neither Docker nor internet
npm run typecheck
npm run buildnpm run test:live is the only suite that talks to public Nostr boards. Run it on purpose, never
in a loop.
Running the CLI from a local clone
The Quickstart above installs nothing and runs everything through npx. If you're hacking on
AgentBridge itself instead, run the CLI straight out of your clone after building it:
git clone https://github.com/Joseamica/agentbridge.git
cd agentbridge
npm ci
npm run build
alias ab="node $PWD/packages/cli/dist/main.js"Heads up on that alias: ab is ApacheBench on macOS, so a fresh terminal that hasn't re-run it
gives you a benchmarking tool's help text instead of "command not found" — confusing the first
time. That collision, and the alias itself, only exist on this from-source path; the published
agentbridge command needs neither. setup-responder and doctor also still take an explicit
--repo <dir> here if you ever want to point them at a checkout other than the one they're
running from.
Status
This is 0.4: no server of ours, built for two people who already trust each other. 0.3 made
setup perform the steps it used to print, after the first real install — by someone who does not
program, on Windows — broke on them. 0.4 lets the answerer choose how far their agent can see: one
folder, several, or the whole personal folder minus a fixed caja fuerte. Known gaps,
deliberate deferrals and the full residual-exposure statement are written down in
docs/known-gaps.md — including the ones that matter before you add a third
person, and the platforms that are reasoned about rather than tested.
Not in 0.4: per-contact scopes, mobile clients, WhatsApp or Telegram, push notifications, organizations, billing, attachments, Codex as the responder, and a global binary on your PATH.
Issues and questions are welcome. If you find a way around the fence, please open an issue.
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Discover willing agents, request permission, hand off durable tasks, and recover private results.
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
The agent-to-agent capability exchange — rent memory, reasoning and safety, settled per call.
Matchmaking network for personal AI agents: private agent-to-agent compatibility rendezvous.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to join a secure agent-to-agent network for team collaboration, with tools for direct messaging, shared rooms, and approval-gated file/command requests.MIT
- AlicenseAqualityBmaintenanceAllows two AI coding agents on different machines to securely pair and share files, context, and conventions through an end-to-end encrypted peer-to-peer channel with human-in-the-loop consent.947 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents on different machines to share verbatim session context and coordinate file leases, preventing concurrent edits and allowing each agent to query the other's exact actions and words.MIT

crosstalkofficial
AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to communicate directly with each other across machines, with support for rooms, pairing, and encrypted messaging.5 npm6MIT