Skip to content

Quickstart

Run a Sovereign Engine node, write through the SDK, and read it back. This guide mirrors the operator + developer getting-started paths from the engine source.

1. Provision a mesh CA (dev)

Use pkg/crypto's dev-mesh CA to mint a CA and per-node leaves (or supply your own PKI and point --tls-cert --tls-key --tls-ca at it):

go
ca, err := crypto.NewMeshCA()
leaf, err := ca.IssueLeaf(nodeID, "localhost")
crypto.WriteCAPEM(ca, "ca.crt")
leaf.WritePEM("leaf.crt", "leaf.key")

Dev mesh only

This is a DEV mesh CA, not production PKI — offline root, intermediate CAs, HSM-backed key custody, OCSP/CRL revocation, and automated rotation are named as post-launch work (ADR-0006).

2. Derive node identity

Pass --identity-seed (an Ed25519 seed); the nodeID is the first 16 bytes of the derived pubkey and must equal engine.localNodeID.

3. Start a node

bash
cmd/sovereign-node \
  --bind :443 \
  --peers peer1:443,peer2:443 \
  --tls-cert leaf.crt --tls-key leaf.key --tls-ca ca.crt \
  --metrics-addr :9100 \
  --control-addr :4433 \
  --arena-mib 4096 \
  --wal-path /var/lib/sovereign/wal \
  --lsm-root /var/lib/sovereign/lsm \
  --gossip-tick 1s \
  --batch-size 100

Defaults are byte-identical-Day-15 conservative: pruning OFF, reaper OFF.

4. Opt into durability & compaction

Once you trust the T_gc floor:

bash
  --wal-checkpoint-interval N \
  --compaction-prune-enable \
  --compaction-prune-horizon-ns <T_gc> \
  --compaction-prune-backoff-ns <backoff>

Add --compaction-reap-enable once you trust your storage layer's existence-probe — the reaper never auto-ONs.

5. Observe

Scrape /metrics for sovereign_* (labelled) and supremum_* (cumulative) series; hit /livecheck for liveness; arm --otel for OTel export to the operator log.

6. Write & read via the SDK

go
client, _ := sovereign.DialWithCerts(":4433", "leaf.crt", "leaf.key", "ca.crt", "node-1")

// Originator path: routes through Gossiper.InsertLocalEvents → bridge.PutLocal (WAL fsync)
err := client.InsertLocal("entity-1", `{"v":42}`)

// Get — Payload only on the originator; peers return the digest, not a value
res, _ := client.Get("entity-1")
// res.PayloadDigest is always set; res.Payload is non-empty only on the originator

root, _ := client.MerkleRoot()

Honest boundary (Ruling 3)

GetResult.Payload is non-empty only on the originator (cache hit); peers return Payload=="" + PayloadDigest!="" because the engine stores only the PayloadDigest on a joined CRDTEntry (TestClientGetOnPeerReturnsDigestNotValue). The SDK does not claim linearizability — InsertLocal returns at LOCAL-apply; peer convergence is eventual (next gossip sweep).

Direct engine use

For direct engine use, the pkg/sync public surface is:

go
eng, err := sync.NewDeltaCRDTEngine(nodeID, initialCounter, arenaSize)
dot := eng.InsertLocal(entityID, entry)      // 0 allocs/op hot path
eng.Join(delta)                              // FROZEN merge-union
remoteDigest := eng.GenerateDigest()         // IBLT
delta := eng.GenerateDelta(remoteDigest)     // minimal missing set; defer delta.Release()
eng.ApplyCRDTDeltaEvent(wire)                // wire-integrity + Join
wire, _ := sync.BuildCRDTDeltaEvent(entityID, payload, entry)

Next

Documentation synthesized from the Sovereign Engine source — 231 .go files, 100% coverage.