npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dolutech/agent-link

v0.1.1

Published

P2P protocol for direct communication between personal AI agents

Readme

AgentLink Protocol

P2P protocol for direct communication between personal AI agents

License: MIT npm version Node.js Version

Version: 0.1.0 | Website


What is AgentLink?

AgentLink is like SMTP for AI agents - any agent, running anywhere, can send a message to any other agent simply by knowing its address.

The Problem

Personal AI agents (like OpenClaw) run on user-owned hardware (Mac Minis, VPS, Raspberry Pi). Today, when two agents on different machines need to communicate, there's no native protocol for it. Current "solutions" are workarounds:

  • Using human chat platforms (Telegram, Discord) as bridges
  • Manually sharing .md files
  • Running multiple agents on the same instance (no real isolation)

Existing protocols (A2A, ACP, ANP) are designed for enterprise/cloud scenarios and don't solve the personal self-hosted agent case.

The Solution

AgentLink Protocol is a lightweight, open P2P protocol that enables personal AI agents to:

  • Discover each other
  • Authenticate cryptographic identities
  • Exchange messages directly, without central servers

Features

  • :lock: Self-sovereign identity with DID did:key
  • :globe_with_meridians: P2P networking with libp2p
  • :closed_lock_with_key: End-to-end encryption with Noise
  • :scroll: Message signing with Ed25519
  • :handshake: Trust levels for permission control
  • :credit_card: Agent Cards - shareable identity cards

Design Principles

| Principle | Description | | -------------------------------- | ----------------------------------------- | | Zero third parties | All communication is direct between peers | | Radical simplicity | Minimal implementation | | Secure by default | Everything encrypted and authenticated | | Framework agnostic | Works with any agent/framework | | Human-controlled permissions | Owner defines what the agent can do |


Architecture

+-------------------------------------------------------------+
|  LAYER 4: APPLICATION (Agent Card, Intents, Capabilities)  |
+-------------------------------------------------------------+
|  LAYER 3: MESSAGE (JSON Envelope, Signature, Types)        |
+-------------------------------------------------------------+
|  LAYER 2: IDENTITY (DID did:key, Ed25519, Self-sovereign)  |
+-------------------------------------------------------------+
|  LAYER 1: TRANSPORT (QUIC, TCP, NAT Traversal, mDNS, DHT)  |
+-------------------------------------------------------------+

Installation

npm install @dolutech/agent-link

Requirements: Node.js >= 20.0.0


Quick Start

import { AgentLinkNode } from "@dolutech/agent-link";

// Create and start your agent node
const agent = new AgentLinkNode({
  name: "My AI Assistant",
  description: "A helpful personal AI agent",
  capabilities: ["messaging", "scheduling"],
  listenPort: 9100,
  enableMdns: true,
});

await agent.start();

console.log("Agent DID:", agent.getIdentity()?.did);
console.log("Agent Card:", agent.getAgentCard());
console.log("Listening on:", agent.getPrimaryEndpoint());

// Stop when done
// await agent.stop();

API Reference

Node

import { AgentLinkNode } from '@dolutech/agent-link';

const node = new AgentLinkNode({
  name: string;              // Required: Agent name
  description?: string;      // Optional: Description
  capabilities?: string[];   // Optional: ['messaging', 'handshake']
  listenPort?: number;       // Optional: Default 9100
  enableMdns?: boolean;      // Optional: Default true
  defaultTrust?: TrustLevel; // Optional: Default 'ask'
});

// Lifecycle
await node.start();
await node.stop();

// Identity
node.getIdentity();  // Returns IdentityKeyPair | null

// Agent Card
node.getAgentCard(); // Returns AgentCard | null

// Contacts
node.getContactBook(); // Returns ContactBook

// Transport
node.getLibp2p();        // Returns Libp2p | null
node.getPrimaryEndpoint(); // Returns string | null

Identity

import {
  generateKeyPair,
  getOrCreateIdentity,
  loadIdentity,
  saveIdentity,
  sign,
  verify,
  publicKeyToDid,
  didToPublicKey,
} from "@dolutech/agent-link";

// Generate a new identity
const identity = await generateKeyPair();
console.log(identity.did); // did:key:z6Mk...

// Get or create persisted identity
const identity = await getOrCreateIdentity();

// Convert between DID and public key
const did = publicKeyToDid(publicKey);
const publicKey = didToPublicKey(did);

// Sign and verify data
const data = new TextEncoder().encode("Hello, AgentLink!");
const signature = sign(data, identity.privateKey);
const isValid = verify(data, signature, identity.publicKey);

// Persist identity
await saveIdentity(identity);
const loaded = await loadIdentity();

Agent Card

import {
  createAgentCard,
  validateAgentCard,
  toJson,
  toLink,
  fromLink,
} from "@dolutech/agent-link";

// Create an Agent Card
const card = createAgentCard({
  did: "did:key:z6Mk...",
  name: "My Agent",
  description: "A personal AI assistant",
  capabilities: ["messaging", "scheduling"],
  endpoints: {
    agentlink: "/ip4/0.0.0.0/tcp/9100",
  },
});

// Validate an Agent Card
const result = validateAgentCard(unknownCard);
if (result.valid) {
  console.log("Valid card:", result.card);
} else {
  console.log("Errors:", result.errors);
}

// Export as JSON
const json = toJson(card);

// Export as shareable link
const link = toLink(card);
// agentlink://did:key:z6Mk...?name=My%20Agent&capabilities=messaging,scheduling

// Parse from link
const parsed = fromLink(link);

Contacts & Permissions

import {
  ContactBook,
  TrustLevel,
  PermissionGuard,
  PermissionResult,
} from "@dolutech/agent-link";

// Initialize contact book
const contacts = new ContactBook();

// Add a contact
await contacts.add({
  did: "did:key:z6Mk...",
  name: "Alice Agent",
  trustLevel: "friend",
  agentCard: card,
  multiaddrs: ["/ip4/192.168.1.1/tcp/9100"],
  autoAccept: ["messaging.*"],
});

// Get contact by DID
const contact = contacts.getByDid("did:key:z6Mk...");

// List all contacts
const allContacts = contacts.list();

// List by trust level
const friends = contacts.listByTrust("friend");

// Update trust level
await contacts.setTrustLevel("did:key:z6Mk...", "trusted");

// Check permissions
const guard = new PermissionGuard();
const result = guard.check("friend", "messaging.send");
// Returns: PermissionResult.ALLOWED

// Check with auto-accept patterns
const result = guard.check("friend", "messaging.send", ["messaging.*"]);
// Returns: PermissionResult.ALLOWED

Trust Levels

| Level | Description | Auto-Accept | | --------- | --------------------------------------- | ----------------- | | blocked | Explicitly blocked, reject all messages | None | | unknown | New/unverified agent | Require approval | | ask | Require human approval for actions | Require approval | | friend | Known agent, limited auto-accept | Based on patterns | | trusted | Full trust, auto-accept most intents | All |


Usage Examples

Two Agents Communicating

// Agent A (Alice)
import { AgentLinkNode } from "@dolutech/agent-link";

const alice = new AgentLinkNode({
  name: "Alice Agent",
  capabilities: ["messaging", "scheduling"],
});

await alice.start();
console.log("Alice DID:", alice.getIdentity()?.did);
console.log("Alice endpoint:", alice.getPrimaryEndpoint());
// Agent B (Bob)
import { AgentLinkNode, TrustLevel } from "@dolutech/agent-link";

const bob = new AgentLinkNode({
  name: "Bob Agent",
  capabilities: ["messaging", "scheduling"],
});

await bob.start();

// Add Alice as a contact
const aliceDID = "did:key:z6Mk..."; // From Alice's console output
await bob.getContactBook().add({
  did: aliceDID,
  name: "Alice Agent",
  trustLevel: TrustLevel.FRIEND,
  agentCard: aliceCard, // Obtained via Agent Card exchange
  multiaddrs: ["/ip4/192.168.1.100/tcp/9100"],
});

Sharing an Agent Card

import { createAgentCard, toLink, fromLink } from "@dolutech/agent-link";

// Create your agent card
const card = createAgentCard({
  did: "did:key:z6Mk...",
  name: "My Assistant",
  capabilities: ["messaging", "scheduling"],
  endpoints: { agentlink: "/ip4/192.168.1.50/tcp/9100" },
});

// Generate a shareable link
const link = toLink(card);
console.log("Share this link:", link);
// agentlink://did:key:z6Mk...?name=My%20Assistant&capabilities=messaging,scheduling

// Someone else can parse it
const parsedCard = fromLink(link);
console.log("Agent name:", parsedCard.name);
console.log("Capabilities:", parsedCard.capabilities);

Permission Management

import {
  ContactBook,
  PermissionGuard,
  PermissionResult,
} from "@dolutech/agent-link";

const contacts = new ContactBook();
const guard = new PermissionGuard();

// Add contact with specific auto-accept patterns
await contacts.add({
  did: "did:key:z6Mk...",
  name: "Trusted Scheduler",
  trustLevel: "friend",
  agentCard: card,
  multiaddrs: [],
  autoAccept: ["scheduling.query", "scheduling.propose"], // Auto-accept these
});

// Check if an intent should be allowed
const trustLevel = contacts.getTrustLevel("did:key:z6Mk...");
const autoAccept = contacts.getByDid("did:key:z6Mk...")?.autoAccept || [];

const result = guard.check(trustLevel, "scheduling.query", autoAccept);

switch (result) {
  case PermissionResult.ALLOWED:
    console.log("Auto-accepted");
    break;
  case PermissionResult.DENIED:
    console.log("Blocked");
    break;
  case PermissionResult.REQUIRE_APPROVAL:
    console.log("Ask user for approval");
    break;
}

Development

# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run dev

# Run tests
npm test

# Test with coverage
npm run test:coverage

# Lint
npm run lint

# Format
npm run format

Project Status

Phase 1: MVP (Complete)

  • [x] Core P2P node with libp2p
  • [x] DID identity with did:key
  • [x] Ed25519 signing and verification
  • [x] Agent Card creation and export
  • [x] Contact book with persistence
  • [x] Trust level system
  • [x] Permission guard

Phase 2: Connectivity (Complete)

  • [x] QUIC transport for faster connections
  • [x] AutoNAT for NAT detection
  • [x] Circuit Relay v2 for NAT fallback
  • [x] DHT discovery (Kademlia)
  • [x] DCUtR hole punching
  • [x] sendMessage for P2P messaging
  • [x] Message protocol for libp2p streams

Phase 3: Intelligence (Planned)

  • [ ] Bridge with LLM
  • [ ] Conversation threads
  • [ ] Offline queue
  • [ ] Complete documentation

Documentation


Contributing

Contributions are welcome! Please read our contributing guidelines:

  1. Fork the repository
  2. Create a branch (git checkout -b feature/new-feature)
  3. Commit your changes (git commit -am 'Add new feature')
  4. Push to the branch (git push origin feature/new-feature)
  5. Open a Pull Request

Security

If you discover a security vulnerability, please do NOT open a public issue. Email: [email protected]


License

MIT License - see the LICENSE file for details.


Acknowledgments

This project was inspired by:

  • libp2p - Modular P2P framework
  • IPFS - Distributed file system
  • OpenClaw - Personal AI agent framework
  • DID - Decentralized Identifiers

"Building the communication infrastructure for the next generation of AI agents."