A peer-to-peer operating system for collaborative, replicated applications.
VOS runs deterministic actors on a JAM-aligned PVM (RISC-V) and replicates them across nodes using either CRDTs (eventual) or Raft (strict). Spaces group actors into per-collaboration roots that converge automatically when peers come online, with no central server and no coordination protocol on the user's critical path.
| Path | What |
|---|---|
vos/ |
Core runtime: PVM host, scheduler, persistence, networking |
vos-macros/ |
#[actor] / #[messages] / #[msg] proc-macros |
vos-raft/ |
Async Raft implementation used by the raft consistency mode |
merkle-crdt/ |
Merkle-DAG CRDT used by the crdt consistency mode |
vosx/ |
Operator-facing CLI (vosx run …, vosx space …) |
actors/ |
Built-in PVM actors bundled into vosx (e.g. space-registry) |
extensions/ |
Native extension plugins loaded by the runtime (e.g. http-gateway) |
zkpvm/ |
ZK proving for PVM bytecode via Stwo |
examples/ |
Sample actors, agents, extensions, wasm guests, space manifests |
containers/ |
Dockerfile + docker-compose for production deployments |
book/ |
The VOS Book (architecture, protocols, applications). Source in docs/ |
# Create a space. Generates per-space identity, runs the bundled
# space-registry briefly to commit a genesis CrdtEvent, derives
# space_id from the resulting DAG root.
vosx space new --name demo
# Run the daemon. Owns the redb, listens on libp2p (auto-port
# loopback by default; pass --listen for a routable addr).
# `--manifest` reconciles a TOML into the registry on startup
# (publishes blobs, installs agents, fires their `on_start`).
vosx space up demo --manifest examples/space-crdt-a.toml &
# Talk to it. `space call` is the floor primitive — any agent,
# any handler. `space publish/install/agents/etc.` are typed
# sugar on top.
vosx space call demo counter inc
vosx space agents demo
vosx space info demo # metadata + daemon liveness + RTT
vosx space export demo > snapshot.toml # round-trip back to TOMLTwo-process CRDT convergence demo (one shell):
just demo-crdt-procs # creates + dials two daemons, both reach count=2
just demo-crdt-sync # in-process variant, no separate processesFor container-based deployments use containers/ —
multi-stage Dockerfile, docker-compose exemplar, healthcheck,
graceful SIGTERM, capability enforcement, and persistent
identity all wired up:
docker compose -f containers/ai-daemon.yml up -dThe Operations Runbook covers identity setup, auth-role grants, capability policy, troubleshooting, and the rest of the day-2 operator surface.
Each [[agent]] in a manifest picks a consistency mode:
| Mode | Replication | Read-from-any-replica | Writes block on |
|---|---|---|---|
ephemeral |
none, in-memory | n/a | nothing |
local |
redb on local disk | n/a | local fsync |
crdt |
merkle-CRDT, eventual | yes | local commit |
raft |
Raft consensus, strict | leader only (today) | quorum ack |
CRDT fits commutative state (counters, sets, LWW maps, append-only logs) where reads-from-anywhere matter. Raft fits strictly sequenced state where divergence corrupts (ledgers, unique-name registries). Modes mix freely per-agent.
Raft requires a cluster membership list (every replica's
node_prefix). See examples/space-raft.toml.
cargo test --all -- --test-threads=1 # full integration suite# host A
vosx space new --name a
vosx space up a --manifest space-crdt-a.toml --listen /ip4/0.0.0.0/tcp/4811 &
vosx space info a # prints the bootnode hint:
# <space_id>@/ip4/.../tcp/4811/p2p/<peer-id>
# host B (paste the bootnode hint)
vosx space join "<bootnode-hint>" --name b
vosx space up b --manifest space-crdt-b.toml --connect /ip4/.../tcp/4811/p2p/<peer-id> &The TOML manifest is a devhelper, not the runtime source of
truth — the registry is. space export re-derives a manifest
from the live registry; space up --manifest is idempotent
reconciliation.
use vos::prelude::*;
#[actor]
pub struct Counter { count: u64 }
#[messages]
impl Counter {
fn new() -> Self { Counter { count: 0 } }
#[msg]
async fn inc(&mut self) { self.count += 1; }
#[msg]
async fn get(&self) -> u64 { self.count }
}#[actor] emits the PVM _start / accumulate entry points.
#[messages] generates the per-handler message types and a
typed CounterRef for host-side calls:
use vos::node::{AgentConfig, VosNode};
use counter::CounterRef;
let mut node = VosNode::new();
let id = node.register(AgentConfig::new(blob));
let counter = CounterRef::at(id);
vos::block_on(counter.inc(&mut &node))?;
let n = vos::block_on(counter.get(&mut &node))?;Compile with the riscv64em-javm target — see
examples/actors/counter/.cargo/config.toml.
An extension is a native .so plugin that runs alongside PVM
agents and gives them OS access — sockets, filesystem, threads,
async runtimes. PVM agents reach the outside world by ctx.ask-ing
extensions. Two kinds:
- Actor — request-driven, same
#[actor]/#[messages]DSL as PVM agents, just compiled as a cdylib. - Service — long-running, owns its own thread + runtime. Use
vos::service_main!(MyService, caps = [...])and provide arun(&mut self, ctx: ServiceCtx) -> i32.
use vos::extension::ServiceCtx;
pub struct MyGateway { /* ... */ }
impl MyGateway {
pub fn new(_args: &[u8]) -> Self { /* ... */ }
pub fn run(&mut self, ctx: ServiceCtx) -> i32 {
while !ctx.is_shutdown() {
// do work, originate ctx.ask_raw(...) calls
}
0
}
}
vos::service_main!(MyGateway, caps = ["net.tcp.bind", "tokio-runtime"]);Install via the manifest:
[[extension]]
name = "gateway"
path = "../target/debug/libmy_gateway.so"
init = { port = 8080 }See extensions/AUTHORING.md for the
full cookbook and docs/extensions.md for the
book chapter. The canonical service-mode example is
extensions/http-gateway/.
VOS is a substrate. Concrete applications are built on top of it as groups of actors and services.
Kunekt is the headline application that the design of VOS was originally shaped around: a protocol for private, decentralized real-time collaboration. It combines the VOS runtime with three protocol layers:
- Sync — Merkle-CRDT documents propagated via the standard
crdtconsistency mode. - Encryption — group ratchet keys (MLS-style) so peers and storage backends only ever see opaque blobs.
- Persistence — encrypted DAG nodes can ride on any content-addressed backend (relay, DHT, DA layer) since storage doesn't need to be trusted.
Kunekt itself is exposed as a built-in actor/service group inside VOS, with
its own slice of the book covering the protocol layers, threat model, and
integrations (Nostr, anonymous credentials, zk-promises). See
book/ → "Applications → Kunekt".
Install the in-repo git hooks once after cloning:
just install-hooksThis points core.hooksPath at .githooks/. Pre-commit gates on
cargo fmt --check, cargo clippy -D warnings, and vosx's unit
tests; pre-push runs the full workspace test suite and just build-pvm
(which also re-asserts the multi-target Cargo warning stays silenced).
Run everything by hand with just verify.