Skip to main content
Glama

AgentLink

ci license: MIT node >= 22.13

Free, open-source messaging between AI agents across devices, networks and services.

AgentLink lets your agents work as a team. That can be pi on your laptop, Claude Code on your workstation, a pi session on a production server, a teammate's Codex, a Python script or a webhook service. Each agent stays where its context, files and permissions already are. Each one can find the others, delegate work to them and get results back.

  • Across devices. Sign in with the same email on every machine. All your agents then share one account and can reach each other by name.

  • Across networks. Agents only make outbound connections, so NAT, home routers and cloud VPCs need no configuration. WebSocket is the default. When a firewall or proxy blocks WebSockets, the client switches to HTTP long-polling on its own. It also respects HTTPS_PROXY.

  • Across services and frameworks.

    • A native pi extension.

    • An MCP bridge for Claude Code, Codex, Cursor, Gemini CLI, OpenCode, Windsurf and Claude Desktop.

    • A CLI that turns any script into an agent.

    • A plain HTTP API for any language.

    • Signed webhooks for services that can't keep a connection open.

    All of them use the same queue and the same delivery guarantees.

  • Across accounts. Two people can link specific agents with a single-use pairing code.

  • Free. MIT license, no paid tiers, no billing code. Run your own relay. The only limits are fair-use limits the operator sets, and all of them default to unlimited or generous values.

 pi (laptop) ─────wss──┐                         ┌── wss ─── pi (prod server)
 Claude Code (MCP) ────┤                         ├── http ── Python script (long-poll)
 Codex (MCP) ──────────┼──── AgentLink relay ────┼── https ─ webhook service
 corporate network ────┘   SQLite · one process  └── wss ─── teammate's agent (paired)
   (http fallback)

Two minutes end to end

agentlink-pi is not on npm yet, so run it from the repository:

# run straight from the repository - npm builds dist/ while installing
npx -y -p github:Zhangbo-cn/agentlink agentlink status

# or keep a checkout
git clone https://github.com/Zhangbo-cn/agentlink && cd agentlink
npm install        # also builds dist/, which an installed package runs from
npm link           # optional: puts agentlink, agentlink-server and agentlink-admin on your PATH

Then, with npx agentlink-pi (after the first npm release) or plain agentlink (from a checkout):

# 1. a relay. http://localhost:8787; without SMTP the sign-in code is printed in this log.
npx agentlink-pi server

# 2. sign in. The first sign-in creates the account; every later one adds a device to it.
npx agentlink-pi login http://localhost:8787 --email you@example.com
#   A 6-digit code was sent to you@example.com.
#   Code: 404812
#   Signed in as you@example.com. Device "laptop" saved.

# 3. an agent on another machine (or another terminal). Whatever the command prints is the reply.
npx agentlink-pi listen --name ci-runner --cap ci,gpu --exec './run-job.sh'

# 4. ask it for something.
npx agentlink-pi send ci-runner "deploy v1.4.2 to staging" --wait 60
#   delivered → ci-runner (msg_B-oBIiYVjHPE)
#   reply ← ci-runner (msg_9aKm3Ql1):
#   deployed v1.4.2 to staging

Point an AI agent at that relay instead of a shell script and it can do the same thing itself: ask it to find a capable agent, delegate the work and report the result.

Related MCP server: mcp-a2a-bridge

Quick start

1. Run a relay (or use one someone else runs)

# Docker + automatic HTTPS
cp deploy/.env.example deploy/.env      # set AGENTLINK_DOMAIN and AGENTLINK_SMTP_URL
docker compose -f deploy/docker-compose.yml up -d --build

# or plain Node (>= 22.13)
npx agentlink-pi server                 # http://localhost:8787; sign-in codes go to the log without SMTP

2. Sign in on each machine with your email

npx agentlink-pi login https://relay.example.com --email you@example.com
# enter the 6-digit code from your inbox

The first sign-in creates your account. Every later sign-in with the same email adds that machine to the same account. If a machine has no email access, you can add it with a one-time code: run agentlink invite on a machine that is already signed in, then agentlink join <server> <code> on the new one.

3. Connect your agents

pi (native: incoming messages start a turn automatically)

pi install npm:agentlink-pi
pi --agentlink-name laptop --agentlink-describe "My laptop; owns the docs repo" --agentlink-caps repo:docs

Inside pi you can also sign in with /agentlink_login you@example.com https://relay.example.com.

Claude Code / Codex / Cursor / Gemini CLI / OpenCode (MCP)

claude mcp add agentlink -- npx -y agentlink-pi mcp --name workstation --framework claude-code

See examples/mcp-configs.md for every client.

Any script (each message is passed to your command; whatever it prints is sent back as the reply)

npx agentlink-pi listen --name ci-runner --cap ci,gpu --exec './run-job.sh'

Any language: examples/python_agent.py uses only the standard library and HTTP long-polling. Webhooks: examples/webhook-receiver.mjs.

4. Ask

Find an agent that can deploy, ask it to roll out v1.4.2 to staging, and tell me when it's done.

Your agent calls agentlink_agents with capability: "deploy" to find a suitable agent, then sends the task with agentlink_send. The reply comes back into your conversation.

How it works

Identity

Account (email) → devices (one per machine, revocable) → agents. An agent is a pi session, an MCP client, a script or a service. A persistent name belongs to the device that created it. Agents without a name are ephemeral, get a random name, and keep their identity across reconnects.

Discovery

Agents publish a profile: framework, description, capability tags, project and host. agentlink_agents lists agents with their profile and live state: idle, busy or offline. It also shows how each one is connected (ws, http or webhook).

Delivery

Messages are stored in SQLite before the sender gets a response. Delivery is at-least-once, and the client removes duplicates by message id. Order is preserved per recipient. If the recipient hasn't acknowledged within 60 s, the message is sent again. Sends with an idempotency key are never delivered or counted twice. Messages to offline persistent agents wait in a queue (7 days by default).

Priority

A followUp waits until the recipient is idle. A steer interrupts the recipient. When a steer is delivered, everything queued before it is delivered with it, so a correction never arrives ahead of what it corrects.

Transports

WebSocket (/v1/ws), HTTP long-poll (/v1/agent/*) and webhooks (signed with HMAC-SHA256 and retried with backoff up to 1 h) all use the same queue.

Files

Up to 5 attachments per message, 25 MiB each by default. Uploads are streamed. Downloads are checked against a SHA-256 hash, can only be fetched by the sender's and recipient's accounts, and never overwrite existing files.

Server configuration

All settings are environment variables. See deploy/.env.example.

Variable

Default

AGENTLINK_SIGNUP

email

email (verified email), invite (admin-created accounts only), open (no verification, LAN only)

AGENTLINK_EMAIL_DOMAINS

–

Limit sign-up to these domains, e.g. your company's

AGENTLINK_SMTP_PROVIDER + _USER + _PASS

–

Sending mailbox: qq, exmail, 163, 126, yeah, 163qiye, aliyun, gmail, outlook, sendgrid or ses. See below

AGENTLINK_SMTP_URL

–

Alternative: smtps://user:pass@host:465. Without either setting, codes are written to the log

AGENTLINK_MAIL_FROM

SMTP login address

Leave empty. QQ, 163 and Gmail reject any other sender

AGENTLINK_WEBHOOKS

public

public (https, public IPs only), private (allow LAN targets), off

AGENTLINK_MONTHLY_MESSAGES

0 (unlimited)

Fair-use limit per account

AGENTLINK_MAX_DEVICES / _MAX_ONLINE_AGENTS

50 / 100

AGENTLINK_MAX_ATTACHMENT_BYTES

25 MiB

AGENTLINK_QUEUE_TTL_SEC

7 days

How long queued messages wait

AGENTLINK_ADMIN_TOKEN

–

Enables the admin API and agentlink-admin

AGENTLINK_METRICS_TOKEN

–

Protects /metrics

AGENTLINK_TRUST_PROXY

0

Use X-Forwarded-For for rate limits

AGENTLINK_DATA_DIR, PORT, HOST, LOG_LEVEL

./data, 8787, 0.0.0.0, info

One relay, two ways in

A single server can serve both a private network and the public internet; nothing in the protocol changes, you just point agents at different addresses.

# Your own devices: a private address (LAN IP or a Tailscale/WireGuard address)
agentlink login http://192.168.1.20:8787 --email you@example.com

# Everyone else: the public hostname, TLS terminated by the reverse proxy
agentlink login https://relay.example.com --email them@example.com

Both entries hit the same database and the same account space, so a device on your LAN and a device on the other side of the internet message each other normally. Set AGENTLINK_PUBLIC_URL to the public hostname (sign-in mails link to it) and AGENTLINK_TRUST_PROXY=1 behind Caddy/nginx so per-IP rate limits see the real client address.

Access control can be layered on top of that:

Who

Setting

Result

Just you

AGENTLINK_SIGNUP=invite

Nobody new gets in unless you invite them

A team

AGENTLINK_SIGNUP=email + AGENTLINK_EMAIL_DOMAINS=yourcompany.com

Only that domain can self-register

You + invited outsiders

AGENTLINK_SIGNUP=invite + agentlink-admin invite them@example.com

Invited people register themselves with a mailed code; everyone else is refused

AGENTLINK_URL=https://relay.example.com AGENTLINK_ADMIN_TOKEN=... agentlink-admin invite them@example.com
AGENTLINK_URL=https://relay.example.com AGENTLINK_ADMIN_TOKEN=... agentlink-admin invites

Running without email at all

Email is only used to verify identity at sign-up / new-device sign-in. Message delivery never touches it. If the relay runs on your own machine or LAN, drop email entirely:

AGENTLINK_SIGNUP=open agentlink-server            # accounts can be created without verification
agentlink signup http://localhost:8787 --account zhang --device mypc

AGENTLINK_SIGNUP=open means anyone who can reach the port can create an account, so keep it on a trusted network (or behind the reverse proxy) — use email or invite for anything public. The other no-SMTP options are agentlink-server code <email> (below) and invite codes via agentlink invite / agentlink join.

Sign-in codes without a mail server

For a self-hosted instance you can skip email entirely and have the server hand you the code:

agentlink-server code you@example.com     # prints a fresh 6-digit code (needs access to the data dir)
agentlink login https://relay.example.com --email you@example.com --code 123456

Sending sign-in emails

Users can sign up with any email address: QQ, Gmail, 163, 126, Outlook, a company domain, and so on. The server only needs one mailbox to send from:

cp deploy/.env.example .env      # then edit .env — the server loads it automatically and it wins over stale shell variables
# .env is gitignored, so the authorization code never ends up in a commit
# or let the server fill it in, with the code hidden while you type it:
agentlink-server set-pass --provider 163 --user you@163.com

# QQ mailbox: Settings → Account → enable POP3/SMTP → generate an authorization code (授权码)
AGENTLINK_SMTP_PROVIDER=qq AGENTLINK_SMTP_USER=yourbot@qq.com AGENTLINK_SMTP_PASS=<授权码>
# NetEase 163/126: Settings → POP3/SMTP/IMAP → enable SMTP → authorization code
AGENTLINK_SMTP_PROVIDER=163 AGENTLINK_SMTP_USER=yourbot@163.com AGENTLINK_SMTP_PASS=<授权码>
# Gmail: enable 2-Step Verification → App passwords
AGENTLINK_SMTP_PROVIDER=gmail AGENTLINK_SMTP_USER=yourbot@gmail.com AGENTLINK_SMTP_PASS=<app password>

agentlink-server test-mail you@example.com      # check the settings before going live
agentlink-server mail-check                      # TCP / TLS / login, reported one stage at a time

Things to know:

  • Use the mailbox's authorization code or app password, not its login password.

  • The sender address must be the mailbox you log in with. Leave AGENTLINK_MAIL_FROM empty and the server fills it in.

  • Personal mailboxes have daily sending limits, and mail from them can end up in spam. For more than a handful of users, use a transactional email service: SendGrid, Amazon SES, Alibaba Cloud DirectMail or Tencent Cloud SES. Configure it with AGENTLINK_SMTP_URL, and set up SPF/DKIM for your own domain.

  • Servers in mainland China usually can't reach smtp.gmail.com. Use QQ or 163 there.

  • Many cloud providers block outbound port 25, so use 465 or 587. All presets already do.

Rate limits (HTTP requests per IP, connection attempts, sends per agent, emails per IP) can be tuned with AGENTLINK_HTTP_BURST, AGENTLINK_HELLO_BURST, AGENTLINK_SEND_BURST, AGENTLINK_EMAIL_PER_IP_HOUR and the matching _PER_SEC variables.

Operations

  • Health check at /healthz, Prometheus metrics at /metrics, JSON logs on stdout.

  • Graceful shutdown on SIGTERM.

  • Online backups with deploy/backup.sh.

  • A systemd unit in deploy/agentlink.service.

  • agentlink-admin to create accounts on invite-only servers, set per-account limits and disable accounts.

Client reference

CLI (npx agentlink-pi <cmd>, or agentlink <cmd> after a global install)

login [server] [--email E]      join <server> <code>      status      invite
devices | revoke <id> | logout
agents [--capability X] [--json]
send <to> <message...> [--file F]... [--wait SECONDS] [--steer]
pair-code --name N | pair <code> --name N | unpair <agent-id> --name N   (cross-account)
listen [--name N] [--exec CMD] [--describe D] [--cap a,b]
mcp [--name N] [--framework F] [--describe D] [--cap a,b]
server
--transport auto|ws|http

Headless machines and CI can skip the credentials file by setting AGENTLINK_SERVER, AGENTLINK_DEVICE_ID and AGENTLINK_DEVICE_TOKEN.

pi commands: /agentlink_login, /agentlink_code, /agentlink_join, /agentlink_status, /agentlink_agents, /agentlink_online, /agentlink_offline, /agentlink_invite_device, /agentlink_devices, /agentlink_revoke_device, /agentlink_pair_code, /agentlink_pair, /agentlink_unpair, /agentlink_logout.

Model tools (pi and MCP): agentlink_agents, agentlink_send, agentlink_status, agentlink_download. MCP clients also get agentlink_inbox (with wait_seconds) and agentlink_set_profile. MCP clients can't be interrupted, so the bridge buffers incoming messages. It adds an "N unread messages" note to every tool result until they are read.

SDK: sdk/client.ts exports AgentLinkClient (self-healing, chooses its transport automatically), Rest, the email sign-in helpers and verifyWebhook.

HTTP API

Device credentials: Authorization: Device <deviceId>:<token>. Agent credentials: Authorization: Agent <agentId>:<credential>.

GET /v1/info

Server version, signup mode, limits, transports

POST /v1/auth/email/start {email}

Email a 6-digit code

POST /v1/auth/email/verify {email, code, deviceName}

Returns device credentials. Creates the account the first time

POST /v1/enroll {code, deviceName}

Join with a one-time device code

GET /v1/me, GET /v1/devices, DELETE /v1/devices/:id, POST /v1/enrollments, GET /v1/agents

Device-scoped

POST /v1/agent/connect {name?, credential?, profile?}

Claim or resume an agent and get its agent credentials

GET /v1/agent/messages?wait=25

Long-poll. Ack with POST /v1/agent/ack {messageIds}

POST /v1/agent/send {to, text, attachments?, replyTo?, deliverAs?, idempotencyKey?}

GET /v1/agent/agents?capability=X, GET /v1/agent/status/:to

Discovery

PUT /v1/agent/profile, POST /v1/agent/activity {activity}

Self-description, busy/idle

PUT /v1/agent/webhook {url}

Push delivery. Returns the signing secret

POST /v1/agent/pair/create, /pair/accept {code}, /unpair {agentId}

Cross-account links

POST /v1/attachments (raw body, x-file-name), GET /v1/attachments/:fileCode

Files

Webhook deliveries

  • The relay sends POST <url> with body {agentId, messages: [...]} and the headers x-agentlink-timestamp and x-agentlink-signature: sha256=HMAC(secret, "<timestamp>.<body>").

  • Answer with any 2xx to acknowledge, optionally with a body of {"ack": [...ids]}.

  • On any other response, the relay retries with exponential backoff.

The WebSocket protocol is the same set of operations as JSON frames {type, id?, payload}: hello, send, ack, activity, list_agents, agent_status, set_profile, pair_*, usage, ping. The server pushes message, pair_added, pair_removed, replaced and revoked. Close codes 4001, 4002 and 4003 tell the client to stop retrying.

Security

See SECURITY.md. In short:

  • TLS in transit, but not end-to-end encryption. Whoever runs the relay can read messages, so run your own relay if that matters.

  • Every operation is checked for account isolation on the server.

  • Only hashes of secrets are stored.

  • Webhooks are protected against SSRF.

  • Peer messages are labelled as coming from another agent, not the user, which lowers the risk of prompt injection.

Development

git clone https://github.com/Zhangbo-cn/agentlink
cd agentlink
npm install        # runs `prepare`, so dist/ is built
npm test           # 46 tests against a real relay: email sign-in, WS/HTTP/webhook interop, proxy + firewall fallback, MCP bridge, CLI
npm run check      # typecheck the server, SDK and CLI, then the pi extension
bash scripts/pack-smoke.sh   # packs a tarball, installs it and passes a real message through it
N=200 M=20 node --experimental-transform-types scripts/loadtest.ts

Sources are TypeScript and run directly with Node's type stripping - no build step while developing (npm run server, npm run cli, npm test). The published tarball ships compiled JavaScript in dist/ instead, because Node refuses to strip types for files inside node_modules. npm run build regenerates it, and scripts/pack-smoke.sh proves the packaged result actually runs.

MIT licensed. See CONTRIBUTING.md.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to discover other agents, publish and match tasks, exchange messages and artifacts, and build transaction-backed reputation over MCP and A2A.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables agents to discover peers on the same host or across connected hosts, exchange messages with them, wait for their replies, and spin up new agents with a task. Messages are tagged with the sender's address so recipients can answer back, with cross-host traffic relayed end-to-end encrypted.
    449 npm
    MIT