HumanityOS is a single Rust crate that compiles into two things: a desktop application with a 3D engine and an offline-first tool suite, and a headless server that anyone can run. Servers federate pairwise, with no central authority and no home server for your account. Your identity is a post-quantum keypair derived from a seed phrase and held on your device, so there is nothing to sign up for and no password to steal.
Everything is public domain. Read the code, run a node, fork it, or take the parts you want.
There is one crate at src/. No Cargo workspace, no sub-crates, no separate
server repository. Cargo features decide what gets compiled in, and the same source tree
produces the desktop app and the server binary.
cargo build --release --features native # desktop app cargo build --release --features relay --no-default-features # headless server HumanityOS # full desktop app: renderer, game, GUI, embedded relay HumanityOS --headless # server only, no GPU, listens on :3210
egui immediate-mode UI over a wgpu PBR renderer, a hecs ECS, rapier3d physics, and kira audio. The same window holds the 3D world and the everyday tools: chat, tasks, notes, files, market, maps.
axum with a WebSocket at /ws and a REST API under /api/.
Storage is embedded SQLite, created on first run at data/relay.db. No
database server, no message broker, no external services.
Plain HTML, CSS, and JavaScript served by nginx. No framework and no build step. The native app is the source of truth for every UI pattern, and the web mirrors it, which is why this page is styled by the same theme tokens the app uses.
Items, recipes, biomes, ships, quests, and planets live in CSV, TOML, RON, and JSON
under data/, validated against schemas in schemas/, and
hot-reloaded by a file watcher. Modding is editing those files.
data/gui/theme.ron. The native
app reads them directly and the web stylesheet is generated from the same file, so a theme
change moves both surfaces at once. Colors are never hardcoded, and a test fails the build
when they are.
There are no accounts, no passwords, and no home server. An identity is a keypair derived from a BIP39 seed phrase on your own machine. Servers store what you publish and verify your signatures. They never hold a credential that could be used to become you.
| Layer | What it uses |
|---|---|
| Identity | ML-DSA-65 (Dilithium3, FIPS 204), deterministically derived from a 24 word BIP39 seed. The public key hex is the account. |
| Message signing | ML-DSA-65 over the message content and timestamp. The relay verifies before it stores, and rejects an invalid signature. |
| Connection proof | Two-phase identify. The server issues a nonce, the client signs hum/identify/v1 with the nonce and the public key, the server verifies before binding the socket. Claiming a key is not enough. |
| Direct messages | Pure ML-KEM-768 (Kyber768, FIPS 203) encapsulation, BLAKE3 as the key derivation, AES-256-GCM for the payload. The envelope is dual sealed for recipient and sender, so both read their history on any device. The relay stores ciphertext it cannot open, and refuses to accept an unencrypted direct message. |
| Federation objects | ML-DSA-65 signatures. Profiles and market objects are signed data that any server may cache and replicate. Newest valid timestamp wins. |
| Identifier | did:hum:<base58(BLAKE3(public key)[..16])>, derived from the signing key, not assigned by a registry. |
| Local vault | AES-256-GCM with PBKDF2-SHA-256 at 600,000 iterations, protecting the seed at rest on your device. |
| Ed25519 | Retained for exactly two jobs: the seed scalar, and the Solana wallet address derived from it. It is not the chat identity. |
Client and server implementations are locked together by cross-language known-answer tests,
so the browser, the desktop app, and the server agree byte for byte on key derivation and on
the message envelope. The canonical inventory lives in the repository, in the Cryptography
section of CLAUDE.md, and it is updated in the same commit as any change.
A server is a place with its own channels, members, and operator. Federation is a bridge between the same room on two servers, and both operators have to opt in: a peer relationship on each side, plus a per-channel toggle. There is no global admin, no registry, and no authority that can revoke a server's membership.
GET /api/federation/servers exposes a node's peer graph, and clients render it as a browsable directory. Adding a server is always the user's choice.Federation shares identities, discovery, and bridged rooms. It does not hand your database to anyone. Rooms you do not federate stay on your machine.
The desktop build and the server are the same program, so any computer that can run the app can host a node. One command starts a relay with an embedded database and no dependencies to install.
HumanityOS --headless PORT=3210 # optional, default 3210 DATABASE_PATH=data/relay.db # optional, default data/relay.db
scripts/provision-vps.sh builds the whole stack from a bare Debian 12 install, nginx and TLS included. The floor is 1 GB RAM, 1 core, and 20 GB of disk. On the live server the relay measures at roughly 20 MB of memory and half a percent of one core.ALLOWED_ORIGINS. The WebSocket origin check, CORS, and the content security policy are all built from that list, so the site runs under your name, not ours./claim <code> with the one-time code the relay prints on first start. From then on, administration happens inside the app rather than over SSH.
One binary can be a chat server, a shared game world, a market directory, and a backup host
for other people's encrypted data. You probably do not want all of that, so the
features block in data/server-config.json switches each capability
on or off.
"features": {
"chat": true, "game": true, "market": true, "vault_backup": true,
"uploads": true, "tasks": true, "voice": true, "live_video": true,
"federation": true, "push": true
}
A disabled feature is refused rather than hidden: the endpoint answers 403 and names the
feature, so a modified client cannot use it anyway. The live manifest is published on
/api/server-info so clients and peers can see what a node offers before trying
to use it. Health, identity, and moderation endpoints are always served, so you cannot lock
yourself out of your own machine.
Full walkthrough: docs/admin/SELF-HOSTING.md.
Providers and offerings are signed objects, not rows a server owns. You sign them with the
same identity you chat with, the server validates them against the public schemas in
schemas/provider.toml and schemas/offering.toml, and other nodes
can replicate and verify them without trusting the node that served them.
curl "https://united-humanity.us/api/v2/objects?object_type=offering_v1" node scripts/import-offerings.mjs \ --server https://united-humanity.us \ --seed-file seed.txt \ --provider provider.json \ --offerings offerings.json
Any HumanityOS node answers the same query for its own directory. Details: docs/admin/market-importer.md.
The work is done in the open, released into the public domain, and shipped in small versioned increments. Humans and AI agents are both first-class contributors, and the onboarding documents say so explicitly.
This is the technical front door. The same project, told mission first, is at
united-humanity.us.
This page ships in the repository at web/home/technical.html as a homepage
flavor, so any self-hoster can choose it for their own node.