cryptopeer-stack
Skill
cryptopeer-stack. Use first in any project that builds on the cryptopeer stack (UDX, dart_libp2p and its packages, Ricochet, go-p2p-forge) to pick the right packages for a P2P task, see how Dart, Go and TypeScript peers connect, and find the detailed skill for each package.SKILL.md (Claude Code, Codex, Cursor) · cryptopeer-stack.md (Boubou) · install:
curl -fsSL https://cryptopeer.net/skills/install.sh | sh -s -- cryptopeer-stack
cryptopeer is a family of open-source peer-to-peer libraries for Dart/Flutter, Go and TypeScript, documented at https://cryptopeer.net. There are three layers, and each builds on the one below:
- UDX: a reliable, multiplexed, QUIC-style transport over UDP.
- dart-libp2p: a full libp2p implementation for Dart and Flutter, plus transports for browsers (WebRTC) and nearby devices (Bluetooth LE) and the protocols built on top (GossipSub, Kademlia DHT, Bitswap, Merkle-CRDTs).
- Ricochet: store-and-forward messaging and storage, modelled on email, so a peer can write to another peer that is offline.
Use this skill to decide what to use, then load the detailed skill for each package you touch. Do not write code against a package from memory: these are not the upstream libp2p packages, and their APIs differ.
Packages
Section titled “Packages”| Package | Language | Install | Skill |
|---|---|---|---|
dart_udx |
Dart | dart_udx: ^4.3.0 |
udx-dart |
github.com/stephanfeb/go-udx |
Go | go get github.com/stephanfeb/go-udx@v0.3.0 |
udx-go |
@go-ricochet/udx, @go-ricochet/libp2p-udx |
TypeScript (Node.js, browser entry) | npm i @go-ricochet/udx @go-ricochet/libp2p-udx |
udx-js |
github.com/stephanfeb/go-libp2p-udx-transport |
Go (go-libp2p) | go get github.com/stephanfeb/go-libp2p-udx-transport@v0.1.8 |
go-libp2p-udx |
dart_libp2p |
Dart | dart_libp2p: ^4.12.0 |
dart-libp2p-host, dart-libp2p-custom-protocol, dart-libp2p-nat-relay |
dart_libp2p_webrtc |
Dart / Flutter | dart_libp2p_webrtc: ^0.1.0 |
dart-libp2p-webrtc |
dart_libp2p_ble |
Flutter (Android, iOS, macOS) | dart_libp2p_ble: ^0.2.0 |
dart-libp2p-ble |
dart_libp2p_pubsub |
Dart | dart_libp2p_pubsub: ^3.1.0 |
dart-libp2p-gossipsub |
dart_libp2p_kad_dht |
Dart | dart_libp2p_kad_dht: ^1.6.0 |
dart-libp2p-kad-dht |
dart_libp2p_bitswap |
Dart | dart_libp2p_bitswap: ^2.0.0 |
dart-libp2p-bitswap |
merkledag |
Dart | merkledag: ^2.0.0 |
merkle-crdt |
dart_libp2p_merkle_crdt |
Dart | dart_libp2p_merkle_crdt: ^2.0.0 |
merkle-crdt-sync |
github.com/stephanfeb/go-ricochet |
Go (server, and a Go client in pkg/client) |
build from source or the .deb (v1.6.0) |
ricochet-server, ricochet-mailbox |
ricochet (ricochet-dart-client) |
Dart / Flutter | ricochet: ^0.3.1 |
ricochet-dart-client |
github.com/stephanfeb/go-p2p-forge |
Go | go get github.com/stephanfeb/go-p2p-forge@v0.2.2 |
go-p2p-forge |
Versions are the latest at the time of writing. Check pub.dev, the Go module
proxy or npm before you pin, and keep every dart_libp2p* package on versions
whose constraints agree (dart pub deps shows the resolution).
Cross-cutting skills: cryptopeer-interop-testing (tests across languages and
processes) and cryptopeer-connectivity-debugging (peers that will not connect,
streams that stall).
Choosing what to use
Section titled “Choosing what to use”| You need to… | Use |
|---|---|
| Send reliable streams over UDP between two processes, no libp2p | dart_udx / go-udx / @go-ricochet/udx |
| Build a Dart or Flutter peer with identities, encryption and many protocols | dart_libp2p (dart-libp2p-host) |
| Let a Go service join Dart peers over UDX | go-libp2p with go-libp2p-udx-transport |
| Let a Node.js js-libp2p node join over UDX | @go-ricochet/libp2p-udx |
| Connect a browser app (js-libp2p) to a Dart or Flutter app | dart_libp2p_webrtc, signalled through a relay |
| Connect phones or Macs with no network at all | dart_libp2p_ble |
| Reach a peer behind NAT | Circuit Relay v2, then hole punching (dart-libp2p-nat-relay) |
| Broadcast to many peers on a topic | GossipSub (dart-libp2p-gossipsub) |
| Find peers or content by key, store signed records | Kademlia DHT (dart-libp2p-kad-dht) |
| Fetch content-addressed blocks from peers | Bitswap (dart-libp2p-bitswap) |
| Shared state that many peers edit offline and merge | merkledag + dart_libp2p_merkle_crdt |
| Deliver to a peer that is offline; mailboxes, documents, feeds | Ricochet (ricochet-server, ricochet-dart-client) |
| A Go request/response service over libp2p streams with codecs and middleware | go-p2p-forge |
A request/response protocol between peers that are online at the same time
needs no extra package: write it on dart_libp2p streams
(dart-libp2p-custom-protocol).
How the pieces connect
Section titled “How the pieces connect” Flutter app ─┐ ┌─ Go service (go-libp2p + go-libp2p-udx-transport) Dart CLI ─┼── UDX/Noise/Yamux ────┼─ Ricochet server (go-ricochet) │ /ip4/…/udp/…/udx └─ Node.js (js-libp2p + @go-ricochet/libp2p-udx) │ ├── WebRTC (/webrtc, signalled via a relay) ── browser (js-libp2p) └── Bluetooth LE (/ble) ── Flutter app nearby- The UDX address is
/ip4/<addr>/udp/<port>/udx(and/ip6/…). Every implementation uses the same one, so Dart, Go and Node.js peers dial each other directly. - dart-libp2p speaks the libp2p wire protocols (multistream-select, Noise, Yamux, Identify, Ping, Circuit Relay v2, DCUtR), so it interoperates with go-libp2p and js-libp2p on a shared transport.
- Ricochet servers are ordinary libp2p peers over UDX, Noise and Yamux. They find each other through GossipSub and relay for clients behind NAT.
Rules that hold everywhere
Section titled “Rules that hold everywhere”- Identity is the key. A peer ID is derived from the host’s private key. Persist the key if the peer must keep its identity across restarts; generating a fresh key each start breaks peerstore entries, DHT records, Ricochet mailboxes and ACLs.
- Trust the connection, not the message. Authorise by the peer ID the Noise handshake proved (the remote peer of the stream), never by an ID a request body claims.
- Upgrade UDX on both ends together. UDX v3 does not interoperate with v2, and a version mismatch is dropped silently: it looks like an unreachable peer, not an error.
- Protocol IDs are a contract. Never change a deployed protocol ID or its
message format in place; add
/name/2.0.0and keep serving the old one while peers migrate. - Close what you open. Hosts, streams, subscriptions and UDX sockets hold ports, timers and memory. Tests that leak them hang or fail in later tests.
- Bound everything you read from a peer. Peers are untrusted: cap message sizes, apply timeouts, validate before acting.
Starting a new project
Section titled “Starting a new project”- Load this skill, then the skills for the packages the task needs.
- Add dependencies with the versions above, checked against the registry.
- Start from a working example rather than from scratch: each repo has
example/(Dart) orexamples/(Go, TypeScript), and https://cryptopeer.net/demos/internet-chat/ is a complete relay + DHT + GossipSub + hole-punching app. - Get two peers talking on loopback in a test before adding NAT traversal,
discovery or a UI (
cryptopeer-interop-testing). - Put the stack rules in the project’s agent instructions. A template is at https://cryptopeer.net/skills/AGENTS.md.
Red lines
Section titled “Red lines”- Do not substitute upstream packages (
libp2pon npm,go-libp2pQUIC, other Dart libp2p ports) for cryptopeer ones in a project built on this stack without being asked: the transports and protocol sets differ. - Do not disable Noise or run plaintext connections outside a test.
- Do not hard-code private keys, relay credentials or Ricochet server keys in source.
- Do not edit generated or vendored native code (for example the WebRTC native build) to work around a bug; report it upstream.
Reference
Section titled “Reference”- Site: https://cryptopeer.net (UDX: /udx/, dart-libp2p: /libp2p/, Ricochet: /ricochet/)
- Skill catalogue: https://cryptopeer.net/skills/ (machine-readable: https://cryptopeer.net/skills/index.json)
- Source: https://github.com/stephanfeb