⚠️ Hobby project — don't take it seriously. Someone having fun building things in their spare time. It is not secure, not complete, and not production-ready. No guarantees, no support, no warranty — don't trust it with anything that matters. Use at your own risk.
Fully decentralized peer-to-peer messaging, file transfer, and apps. No central server. No accounts. Just a keypair.
Discovery and signaling ride Tor, so your IP stays hidden from the network. Once two peers mutually agree to connect, they swap real IPs — encrypted to each other's keys — and switch to a direct QUIC connection for speed. Your IP is only ever revealed to people you explicitly accept. And the daemon doesn't stop at chat: it's a platform that hosts services, each with its own identity and connection policy.
DISCOVER → SIGNAL → GATE → VERIFY → IP SWAP → NAT TRAVERSAL → DIRECT QUIC
over Tor (anonymous, slow) only after consent (direct, fast)
- Private by default — all discovery and signaling traffic routes through Tor hidden services. Real IPs are revealed only to accepted peers.
- Bitcoin-style post-quantum identity — a Dilithium (ML-DSA-65) keypair
anchors your
E…address, with a bound Ed25519 key for fast per-message signing and transport. No registration, no server. - Direct connections — after mutual consent, peers connect over QUIC / TLS 1.3 with an automatic NAT-traversal cascade (UPnP → hole punch → relay → Tor fallback).
- A platform, not an app — the daemon hosts named services, each with its own derived identity, default-deny ACL, and message stream. Install, supervise, and distribute them through signed registries.
- One binary, many faces — daemon, terminal UI, attach mode, CLI diagnostics, an embedded web client, and a native desktop shell, all in one executable.
- Pluggable signaling — Tor for real deployments, plus same-host
loopbackand LANmdnsbackends for fast dev loops.
The daemon is the substrate; services are the inhabitants — each one
registers, gets its own E… address derived from the node seed, declares its
own connection policy, and gets its own stream. Chat and the web UI are just the
two built-in services. The interesting ones are external:
| Service | What it is | Platform primitive it shows off |
|---|---|---|
| PUG | a .NET matchmaking library — queues, matchers, private lobbies, sessions | introductions → direct peer-to-peer QUIC, no grants |
| Jeff | a single-user AI companion (Ollama + pgvector memory) | supervised installs, env-overlay secrets, stable identity across upgrades |
| gomp | a decentralized, self-hostable take on a Discord server | launched-app lifecycle, host-led rooms, services bringing their own frontend |
Write them in Python or .NET against the SDKs; distribute and run them through the registry + supervisor. The whole story is in docs/services.md.
# Go-only build (daemon + TUI, no embedded web UI) — needs just Go.
make build-dev
# Run the daemon + interactive terminal UI.
./bin/ensembleThat's enough to kick the tyres. The default tor signaling backend needs a
tor binary in $PATH (Fedora: sudo dnf install tor); for a Tor-free local
loop, add --signaling=loopback. Full build (with the web UI), cross-compiles,
and the dev toolchain are in docs/setup.md.
1. DISCOVER — Query the DHT over Tor to find the peer's .onion address
2. SIGNAL — Dial that .onion, send a connection request (addresses only)
3. GATE — Responder checks its contacts/ACL; unknown peers prompt the user
4. VERIFY — 3-step handshake: mutual identity proof via signatures
5. IP SWAP — Encrypt real IPs to each other's public keys, exchange over Tor
6. NAT — UPnP (2s) → hole punch (10s) → relay (15s) → Tor fallback
7. CONNECT — QUIC handshake with Noise authentication
8. DATA — Chat and file transfer at full speed
The signaling channel is anonymous and slow; the data channel is direct and fast; the handover only happens after consent. The full architecture, layers, and protocol are in docs/architecture.md.
Clients: TUI (in-process) | TUI (attach) | Web SPA | SDKs (Python / .NET)
------------------------------------------------------------------------------
gRPC API (api/proto/ensemble.proto) — the same surface for every client
------------------------------------------------------------------------------
Node (Daemon Core) — orchestrates all subsystems
------------------------------------------------------------------------------
Service Registry | App Layer (chat, files, contacts) | Transport (QUIC)
Signaling (Tor hidden services) | Discovery (Kademlia DHT over Tor + mDNS)
| Doc | What's in it |
|---|---|
| docs/setup.md | Prerequisites, builds, cross-compile/ARM, dev toolchain |
| docs/running.md | Every way to run it: TUI, headless, attach, signaling backends, web UI, Pi, metrics |
| docs/commands.md | Full CLI reference — every subcommand, flag, env var, and TUI keybinding |
| docs/architecture.md | How it's built: layers, subsystems, identity, protocol, project structure |
| docs/security.md | The trust model: identity, the handshake, service ACLs, install gating |
| docs/services.md | The service platform + the PUG / Jeff / gomp showcase |
| docs/creating-a-service.md | Build, package, publish, and run your own service |
| docs/adr/ | Architecture Decision Records — why things are the way they are |
| ui/README.md | The embedded Solid.js web client |
| clients/python · clients/dotnet | The service SDKs |
- Go — single binary, cross-platform.
- libp2p — QUIC, yamux, TLS 1.3, Noise, AutoNAT, DCUtR.
- Tor — via bine; embedded in-process
through go-libtor (cgo) on
linux/amd64, external
torbinary everywhere else. - Dilithium + Ed25519 + Base58Check — post-quantum Bitcoin-style identity.
- Protobuf + gRPC — API and wire protocol (server, both SDKs, browser via gRPC-Web).
- Bubble Tea — terminal UI. Gio — native desktop shell.
- Solid.js + Vite — web client, embedded via
go:embed.
MIT — see LICENSE.