Abracadabra Server

Real-time sync, no drama.

A single Rust binary that speaks CRDTs, stores documents, authenticates users, deduplicates uploads, and hooks into every phase of its own lifecycle.
Abracadabra Server

One server. Every document, live.

The backend that makes the multiplayer real. It speaks documents, not rows — self-host the binary or let us run it for you.

One Rust binary, ~14 MB — Raspberry Pi, Fly.io, or beside your Postgres
Live cursors, presence and CRDT merges in under a millisecond
SQLite for a small team, Postgres for a company — same protocol
MCP clients join as real users, under the same permissions you have
Passkey login, six roles, every upload deduped by SHA-256
REST + WebSocket built in, 34 hook points. MIT, no open-core trap
0documents
0users
0msp99 latency
0ops/s
Actor model

One Tokio actor per document.

Each loaded document owns its own task. Updates arrive in batches of up to 100, flushed to SQLite every 100 ms, broadcast in ~1 ms.

  • Zero locks — DashMap routes to the right actor.
  • Up to 100 updates coalesced per SQL transaction.
  • Broadcasts land on every connected client in under a millisecond.
  • Auto-unload after 300 s idle — reloads on next update.
document_store.rs
live
Binary wire protocol

8 message types. One WebSocket.

Sync, Awareness, Auth, Subdoc, Stateless, Close, SyncStatus, QueryAwareness — all multiplexed over a single connection.

  • VarInt / VarString wire format — compact and fast.
  • Sync uses state vectors — only deltas cross the wire.
  • Multiplex many docs over one connection.
  • SyncStatus acks every applied update.
ws://abra · v2
multiplex
client A
abracadabrasync · auth · broadcast
client B
Sync
Awareness
Auth
Stateless
Subdoc
Query
Status
Close
Identity · RBAC

Six roles, resolved recursively.

Password or Ed25519 challenge-response. JWT in, effective role out — computed through the document tree with a recursive CTE.

  • Passwordless by default — WebAuthn PRF compatible.
  • Inheritance resolved down the parent chain.
  • JWT 7-day (password) or 4-hour (crypto) TTLs.
  • Device sessions + pairing invites for multi-device.
identity · permission
rbac
role hierarchy
Servicebypass all checks
L5
Adminadmin routes
L4
Ownermanage + write
L3
Editorwrite docs
L2
Viewerread + awareness
L1
Observerread only
L0
Ed25519 challenge
POST /auth/challenge
································
32-byte nonce · 60 s TTL
sign(challenge, sk)
································
client-side · private key never leaves device
POST /auth/verify
JWTvalid 4h
server checks signature → issues JWT
Storage

SQLite, or Postgres.

One sqlx-backed storage layer, two dialects. SQLite runs in WAL mode with concurrent readers and a serialized writer — one file, zero ops. Flip the URL to Postgres and writes fan out in parallel under MVCC.

  • SQLite WAL mode — many readers, never blocked by writers.
  • SQLite serializes writes — one writer at a time, engine-enforced.
  • Postgres backend unlocks true parallel writes under MVCC.
  • Flip the URL in [database] — same schema, same API.
database · pool
sqlite · wal
read · 320/32
write · 1IDLE
WALjournal_mode = WAL
Content-addressed storage

SHA-256 is the filename.

Content-addressed uploads deduplicate identical bytes automatically. Reference counts track liveness. Orphans are swept in the background.

  • Same bytes, same blob — twice the refs, zero duplicate disk.
  • Every file identifiable by its 256-bit hash.
  • Orphan sweeper reclaims unreferenced blobs.
  • Path traversal hardened at the storage boundary.
upload_service.rs
dedup
incoming
sha-256
file_blobs · content-addressed
Extension system

Thirty hooks. Native or Wasm.

Drop in custom logic at 30+ points across nine phases: server lifecycle, HTTP, auth, connections, documents, sync, permissions, uploads, snapshots.

  • Native Rust via the Extension trait.
  • Wasm components via wasmtime + WIT.
  • before_update can transform updates in-flight.
  • First error short-circuits the chain.
extension_registry.rs
30+ hooks
POST /docs/:id
on_request
on_auth
on_connect
on_load_document
before_update
on_update
on_stateless
on_upload
response
nativeRateLimit
on_request · <1 msok · 23/100
wasmSchemaValidation
before_updateupdate ✓
wasmWebhook
on_updateidle
Core services

Spaces. Chat. Notifications.

Three first-class services on one stateless wire — a pinned hub space, persistent messaging, and notifications that issue themselves on mention. No extra endpoints, no add-ons to wire up.

  • Every server has a hub — the pinned root space.
  • Chat uses stateless frames — no extra endpoints.
  • Notifications auto-issue on chat mentions.
  • Seeded on boot from [[spaces.seed]].
core · spaces · chat · notify
3 services
Spacesis_hub=true
Hubroot
Teamshared
Personalprivate
Chatchat:send
Notificationsnotify:*
Deploy

One binary. Everywhere.

Cross-compiled statically on every push. Drop on a Pi, ship to Fly.io, run in Docker, leave on a VM.

Linux · x86_64

single binary · ~14 MB

Linux · arm64

single binary · ~13 MB

macOS universal

single binary · ~15 MB

Windows · MSVC

single binary · ~14 MB

Raspberry Pi1 watt
Docker1 line
Fly.io1 region
Bare VM1 ssh

Start your own server.

Run curl -fsSL https://abr.ac/install.sh | sh, point your app at ws://localhost:3000/ws. That's it.