SNAP - Signed Network Agent Protocol. Secure agent-to-agent (A2A) communication with cryptographic identity, built on Bitcoin Schnorr signatures and Nostr.
snap-protocol is an early-stage TypeScript project in the AI payments / x402 ecosystem, focused on a2a-protocol, agent-communication, agent-protocol, agent-to-agent. It currently has 3 GitHub stars and 0 forks, and sits alongside related tools like beam-protocol, capiscio-sdk-python, mxp-js, agent-matrix, capiscio-python, a2a-go.
AI agents authenticate themselves with a keypair instead of API keys.
Agent generates a key. Agent signs its requests. Service verifies the signature. Done. No API keys to provision. No OAuth to configure. No CA to run.
Traditional: Agent gets credentials from a trusted 3rd party (CA, IdP, admin) → service trusts the 3rd party
SNAP: Agent generates its own keypair → signs requests → service verifies directly (no 3rd party needed)
POST /api/tasks
{
"from": "bc1pabc123...",
"method": "service/call",
"payload": { "name": "query_database", "arguments": { "sql": "SELECT 1" } },
"timestamp": 1770163200,
"sig": "e5b7a9c3..."
}
The service verifies the Schnorr signature and checks from against an allowlist of public keys. No shared secret ever exists.
Why is this better than API keys? Public keys are not secrets. You can store allowlists in plaintext, commit them to git, even publish them. Leaking an allowlist has no cryptographic impact. Leaking an API key is a security incident. See Design Decisions for the full trade-off analysis.
Does this require Bitcoin? No. SNAP uses Bitcoin's cryptographic standards (Schnorr signatures, bech32m encoding) but has zero dependency on the Bitcoin network. No blockchain, no transactions. Details →
npm install @snap-protocol/core
Sign a request (agent side):
import { randomBytes, randomUUID } from 'crypto';
import { KeyManager, MessageBuilder, MessageSigner } from '@snap-protocol/core';
const privateKey = randomBytes(32).toString('hex');
const { address } = KeyManager.deriveKeyPair(privateKey);
const signer = new MessageSigner(privateKey);
const signed = signer.sign(
new MessageBuilder()
.id(randomUUID())
.from(address)
.method('service/call')
.payload({ name: 'query_database', arguments: { sql: 'SELECT 1' } })
.timestamp(Math.floor(Date.now() / 1000))
.build()
);
Verify (service side):
import { MessageValidator } from '@snap-protocol/core';
MessageValidator.validate(signed); // throws if signature/timestamp invalid
const allowlist = ['bc1p...agent1', 'bc1p...agent2'];
if (!allowlist.includes(signed.from)) throw new Error('Not authorized');
// See security-practices.md for rate limiting and replay protection
That's Auth. For the full agent-to-agent experience (discovery, tasks, streaming), see the Tutorial.
SNAP's core is authentication. Discovery and communication are optional layers you add when you need them:
┌─────────────────────────────────────────────┐
│ Communication (optional) │
│ message/send · tasks/* · streaming │
├─────────────────────────────────────────────┤
│ Discovery (optional) │
│ Agent Card · Nostr relays · HTTP well-known│
├─────────────────────────────────────────────┤
│ Auth (core) │
│ Keypair identity · Schnorr signatures │
│ Timestamp freshness · Replay protection │
└─────────────────────────────────────────────┘
Auth (core) — Every agent has a cryptographic identity (P2TR address). Every message is signed. Services verify the signature and check an allowlist. This layer works standalone via service/call.
Discovery (optional) — Agents publish capability cards to Nostr relays or HTTP well-known endpoints. Other agents query by skill, name, or identity.
Communication (optional) — Structured methods (message/send, tasks/*), task lifecycle, and streaming over HTTP, WebSocket, or Nostr. Concepts inspired by A2A.
Use as much as you need. Auth alone replaces API keys. Add Discovery to find agents. Add Communication for full agent-to-agent collaboration.
An agent publishes its card to Nostr:
{
"kind": 31337,
"tags": [
["d", "bc1p5d7rjq7g6rdk2yhzqnt9dp8wvscrplqk0z..."],
["name", "Code Assistant"],
["skill", "code-generation", "Code Generation"],
["endpoint", "http", "https://agent.example.com/snap"]
],
"content": "{\"name\":\"Code Assistant\",\"identity\":\"bc1p5d7rjq7g6rdk2...\",\"endpoints\":[...],\"skills\":[...]}"
}
Another agent finds it and sends a request:
{
"id": "msg-001",
"from": "bc1pabc123...",
"to": "bc1p5d7rjq7g6rdk2yhzqnt9dp8wvscrplqk0z...",
"type": "request",
"method": "message/send",
"payload": {
"message": {
"messageId": "inner-001",
"role": "user",
"parts": [{ "text": "Write a login form in React" }]
}
},
"timestamp": 1770163200,
"sig": "a1b2c3d4..."
}
That's it. No API keys. No OAuth. No central registry.
Start here:
| Document | Description |
|---|---|
| Tutorial | Build your first SNAP agent (10 min) |
| Use Cases | Why agents need self-sovereign identity |
| Core Concepts | Identity, discovery, and authentication basics |
| Design Decisions | Why SNAP chose X over Y (mTLS, JWT, DID, etc.) |
Specification:
| Document | Description |
|---|---|
| Agent Card | How agents describe themselves |
| Messages | Request/response format and semantics |
| Transport | HTTP, WebSocket, and Nostr transport |
| Authentication | Schnorr signature authentication |
| Discovery | Finding agents on Nostr |
| Constraints | Field validation rules and limits |
| Errors | Error codes and handling |
| Security Practices | Implementation security guidance |
For AI-assisted development:
| Resource | Description |
|---|---|
| Agent Skills | Skills for AI coding agents (Claude Code, Cursor, Codex, etc.) |
| llms.txt | Documentation index for MCP tools (Context7, mcpdoc) |
Install skills: npx skills add WilliamPenrose/snap-protocol — see skills setup guide for IDE integration.
MCP defines how agents discover and call tools. SNAP adds an authentication layer on top — wrap any MCP tool call in a SNAP service/call envelope and the service can verify the caller's identity via signature instead of API keys.
A2A — SNAP is inspired by Google's A2A Protocol and adopts similar semantic concepts (Task, Message, AgentCard) but uses a different wire format with built-in Schnorr authentication. Not wire-compatible. See Design Decisions for a detailed comparison.
🚧 v0.1 Draft — This is an early draft. Expect breaking changes. Feedback welcome!
implementations/typescript/)service/call, optional to)We'd love your input. See CONTRIBUTING.md for guidelines.
docs/): CC BY 4.0 — see docs/LICENSEimplementations/): MITSNAP is not affiliated with Google or the A2A Protocol project. We simply build on their excellent work.
SMTP for AI agents. The open communication protocol for agent-to-agent communication. 🌊
Runtime security middleware for A2A (Agent-to-Agent) protocol agents. Provides always-on validation, signature verification, and rate limiting for AI agent interactions.
🚀 Simplify AI agent communication with the high-performance MXP JavaScript/TypeScript SDK, designed for efficient binary protocol interactions.
Matrix-style inbox and messaging layer for AI agents, with Lambda Lang transport and a lightweight Next.js web UI.
🚀 Access and manage the CapiscIO CLI easily with this Python wrapper, ensuring optimal performance across your system and architecture.
Golang SDK for A2A Protocol
An open SDK for agentic payments. Let AI agents make payments, hold funds, and move money across chains with policy enforcement and human approval built in.
Client SDK for the Vybe x402 API. Pay-per-call USDC over HTTP and prepaid-credit WebSocket streaming for Vybe's Solana analytics API. Built for AI agents.
Rust SDK for the Machine Payments Protocol
Building blocks for Agentic payments (x402, MPP, AP2) for TypeScript, Rust, Go, Python, Ruby, PHP, Lua, Kotlin and Swift.
Opinionated React Native crypto x AI chat app boilerplate with embedded wallet support, conversational AI, and dynamic UI component injection
A fully modular, framework-agnostic, easy-to-extend SDK for building complex X402 payment integrations.