A decentralized trust infrastructure for real-life communities. People meet in person, verify each other's identity via QR code, and build reputation through attestations over time.
No central server sees your data. Everything is end-to-end encrypted and stored locally.
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β VERIFY β βββΊ β COLLABORATE β βββΊ β ATTEST β
β β β β β β
β Confirm identityβ β Share encrypted β β Build reputationβ
β by meeting in β β content (tasks, β β through real β
β person (QR scan)β β calendar, maps) β β actions β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
Verification β Trust. Verification only confirms: "This is really that person." Actual trust is built through attestations over time.
- Demo App: web-of-trust.de/demo
- CRDT Benchmark: web-of-trust.de/benchmark β measure Yjs vs Automerge on your device
- Relay:
wss://relay.utopia-lab.org - Profiles:
https://profiles.utopia-lab.org
The system is built on swappable adapters β same interfaces, different implementations. This allows experimenting with different CRDT frameworks, messaging protocols, and storage backends without touching application code.
βββββββββββββββββββββ
β Your App / Demo β
βββββββββββ¬ββββββββββ
β
ββββββββββββββββββββββββββββ΄βββββββββββββββββββββββββββ
β wot-core β
β βββββββββββ ββββββββββββ ββββββββββ βββββββββββββ β
β β Storage β β Reactive β β Crypto β β Discovery β β
β βββββββββββ ββββββββββββ ββββββββββ βββββββββββββ β
β βββββββββββββ βββββββββββββββ βββββββββββββββββ β
β β Messaging β β Replication β β Authorization β β
β βββββββββββββ βββββββββββββββ βββββββββββββββββ β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ
β
ββββββββββββββββββ΄βββββββββββββββββ
β adapter-yjs / adapter-automerge β
ββββββββββββββββββ¬βββββββββββββββββ
β
ββββββββββββββββββΌβββββββββββββββββ
β β β
βββββββ΄ββββββ ββββββββ΄ββββββ βββββββββ΄ββββββββ
β wot-relay β β wot-vault β β wot-profiles β
βββββββββββββ ββββββββββββββ βββββββββββββββββ
| Adapter | Purpose | Implementation |
|---|---|---|
| StorageAdapter | Local persistence, CRUD | Yjs (default) or Automerge |
| ReactiveStorageAdapter | Live queries, subscriptions | Observables on CRDT changes |
| CryptoAdapter | Signing, encryption | WebCrypto (Ed25519, X25519, AES-256-GCM) |
| DiscoveryAdapter | Public profile lookup | HTTP + offline cache |
| MessagingAdapter | 1:1 message delivery | WebSocket Relay (ACK + Outbox) |
| ReplicationAdapter | Encrypted CRDT Spaces | Yjs or Automerge + E2EE + GroupKeys |
| AuthorizationAdapter | Capabilities / permissions | UCAN-inspired, offline-verifiable |
Three CRDT-agnostic services β they only see encrypted bytes, never plaintext:
| Service | Transport | Purpose |
|---|---|---|
| wot-relay | WebSocket | Real-time sync + delivery ACK |
| wot-vault | HTTP | Encrypted backup for new device restore |
| wot-profiles | HTTP | Public profile discovery (JWS-signed) |
Data is also persisted locally in IndexedDB (CompactStore) for offline access.
| Package | CRDT | Runtime | Notes |
|---|---|---|---|
| adapter-yjs | Yjs | Pure JavaScript (69KB) | Default. Fast on all devices. |
| adapter-automerge | Automerge | Rust β WASM (1.7MB) | Alternative. Heavier on mobile. |
Switch at startup with VITE_CRDT=automerge. Both pass the same 11 end-to-end tests. Try the in-browser benchmark to compare on your device.
- BIP39 Mnemonic β 12-word recovery phrase (German wordlist)
- Ed25519 β Signing (via @noble/ed25519)
- X25519 β Key agreement (ECDH)
- did:key β W3C Decentralized Identifier
- HKDF Master Key β Non-extractable CryptoKey, hardware isolation when available
- Encrypted seed storage β PBKDF2 (600k iterations) + AES-GCM in IndexedDB
All data is encrypted before it leaves the device. The relay server only sees ciphertext.
- Symmetric: AES-256-GCM (CRDT updates, group content)
- Asymmetric: X25519 ECIES (key exchange, 1:1 messages)
- Envelope Auth: Ed25519-signed message envelopes
- Group Keys: Per-space key with generation-based rotation
- Group Spaces β CRDT-based collaboration (ReplicationAdapter)
- Selective Sharing β Item-level encryption keys
- 1:1 Delivery β Attestations, verifications via Relay
- Node.js 22+
- pnpm 9+
# Install dependencies
pnpm install
# Start demo app (default: Yjs)
pnpm dev:demo
# Start demo app with Automerge
VITE_CRDT=automerge pnpm dev:demo
# Start landing page
pnpm dev:landing
# Run tests
pnpm test # all packages
pnpm test:e2e # Playwright E2E tests
# Build
pnpm build:coreweb-of-trust/
βββ packages/
β βββ wot-core/ # @web_of_trust/core β Core library
β βββ adapter-yjs/ # @web_of_trust/adapter-yjs β Yjs CRDT adapter (default)
β βββ adapter-automerge/ # @web_of_trust/adapter-automerge β Automerge CRDT adapter
β βββ wot-relay/ # WebSocket Relay Server (Node.js, SQLite)
β βββ wot-vault/ # Encrypted Document Store (HTTP, SQLite)
β βββ wot-profiles/ # Public Profile Service (HTTP, SQLite, JWS)
βββ apps/
β βββ demo/ # Demo App (React 19, i18n, Dark Mode)
β βββ benchmark/ # CRDT Benchmark (Yjs vs Automerge)
β βββ landing/ # Landing Page
βββ docs/ # Architecture docs & specifications
| Package | Description | Links |
|---|---|---|
@web_of_trust/core |
Core library β identity, crypto, adapters, services | npm |
@web_of_trust/adapter-yjs |
Yjs CRDT adapter (default) β pure JS, 76x faster on mobile | |
@web_of_trust/adapter-automerge |
Automerge CRDT adapter β RustβWASM | |
wot-relay |
WebSocket Relay Server β message forwarding, delivery ACK, SQLite | |
wot-vault |
Encrypted Document Store β append-only, capability auth, SQLite | |
wot-profiles |
Public Profile Service β JWS verification, REST API, SQLite |
// Core β identity, crypto, messaging
import {
WotIdentity,
WebCryptoAdapter,
HttpDiscoveryAdapter,
WebSocketMessagingAdapter,
OutboxMessagingAdapter,
ProfileService,
EncryptedSyncService,
GroupKeyService,
} from '@web_of_trust/core'
// CRDT adapter β choose one
import { YjsReplicationAdapter } from '@web_of_trust/adapter-yjs'
// or: import { AutomergeReplicationAdapter } from '@web_of_trust/adapter-automerge'
// Create identity from 12 magic words
const identity = new WotIdentity()
await identity.create('my-passphrase', true)
console.log(identity.getDid()) // did:key:z6Mk...| Package | Tests | Framework |
|---|---|---|
| wot-core | 392 | Vitest 4.1.0 |
| wot-relay | 24 | Vitest 4.1.0 |
| wot-vault | 27 | Vitest 4.1.0 |
| wot-profiles | 25 | Vitest 4.1.0 |
| Demo (Unit) | 59 | Vitest 4.1.0 |
| Demo (E2E) | 7 | Playwright |
| Total | 534 |
All 11 E2E tests pass with both CRDT adapters (Yjs and Automerge).
- Onboarding β Create identity with 12 Magic Words + passphrase
- Recovery β Restore identity from seed on any device
- QR Verification β In-person identity verification via camera
- Contacts β Manage verified contacts
- Attestations β Attest skills/properties, receive, publish
- Spaces β Encrypted group collaboration (CRDT)
- Profile Sync β JWS-signed profiles published to wot-profiles
- Public Profile β Viewable without login
- Multi-Device β Sync via Relay + Vault
- Offline-First β Local data, offline banner, outbox queue
- i18n β German + English
- Dark Mode β Fully supported
- Debug Panel β Persistence metrics, relay status, CRDT info
Note: Most specification documents are in German. The implementation status is documented in English in CURRENT_IMPLEMENTATION.md.
| Document | Description |
|---|---|
| Current Implementation | What's built, what works, architecture decisions |
| NLNet Application | Funding application (NGI Zero Commons Fund) |
| Adapter Architecture v2 | 7-adapter specification |
| Framework Evaluation | 16 frameworks evaluated |
| DID Methods Comparison | 6 DID methods evaluated (did:key confirmed) |
| Vault Sync Architecture | Three sync patterns |
| Social Recovery | Shamir Secret Sharing concept |
| Threat Model | STRIDE analysis |
| Encryption Protocol | E2E encryption design |
- Real Life Stack β Modular app toolkit for local communities, built on Web of Trust
We're looking for:
- Communities who want to try it
- Feedback on UX and concept
- Developers who want to build with us