Client / server

Arkeion starts life as an embedded library, but it also ships a server. Not “another SQL server”: the point is that git and audit semantics are first-class in the protocol — a branch per session, time-travel (AS OF), cryptographic verify over the wire, and diff/merge as remote calls. The goal is a verifiable cloud rather than a “trust us” one, which is the same thesis as sovereignty.

A native protocol, not pgwire

Speaking Postgres’s wire protocol (pgwire) would buy an instant ecosystem, and it was seriously evaluated. Native won because the things that make Arkeion worth connecting to — attaching to a branch, migrating, diff, merge, verify over the connection — don’t fit pgwire without abusing it with session variables and ad-hoc syntax. A pgwire compatibility layer for plain CRUD remains a possible later addition; what an Arkeion server sells is precisely what pgwire cannot say.

Open-core, drawn at the repository line

The open-core boundary is drawn at the repo level, so the open library stays pure and the commercial server never has to touch it.

Arkeion embedded engine + wire protocol MIT / Apache-2.0 client Rust SDK / driver MIT / Apache-2.0 the open line arkeiond the server daemon proprietary
Engine, protocol, and client are open so adoption is frictionless; the server is where the commercial cloud lives.
  • The engine and protocol ship together and stay open. The wire protocol is hand-written — no serde — and reuses the engine’s own varint and value encoding.
  • The client is a synchronous Rust SDK (use_branch, execute, query, query_as_of, verify). Keeping it open is what makes the server adoptable.
  • The server, arkeiond, is proprietary. It is thread-per-connection with no async runtime, which suits the single-writer engine and keeps the supply chain small. Offering it as a hosted service requires Syrakon’s prior approval.

A session is a view onto a branch

One TCP connection is one session, and a session is a view onto a branch (main by default, switchable). The engine’s single writer serialises the writes of every client; reads run against snapshots — including AS OF — in parallel, and never block.

session · main session · feat-x session · main single writer serialises all writes one file reads (snapshots, AS OF) run in parallel — never blocked
Every session sees its own branch; writes queue through one writer, reads never wait.

Two consequences follow from the single writer. The server’s write ceiling is the writer’s ceiling, so group commit — amortising the per-commit fdatasync across clients — is a planned optimisation. And because an open transaction holds the write lock for its whole life, timeouts and cancellation are needed so one stuck client can’t stall the rest.

On the wire

Framing is deliberately boring: a length-prefixed frame carrying a tagged payload, capped at 64 MiB so a bad frame can’t exhaust memory.

frame   = [u32 LE length][payload]
payload = [u8 tag][fields...]         # fields use the engine's varint + value codec

tag → message
  Hello / Welcome        handshake
  UseBranch              switch the session's branch
  Execute → Affected     a write; returns rows affected
  Query{AS OF} → Rows     a read, optionally against a past version
  Verify → Audit         cryptographic check; returns the chain hash
  Error                  structured failure
u32 LE length ≤ 64 MiB payload u8 tag fields — varint + value codec read length, then exactly that many bytes
Length first, then a tagged payload — enough to frame every message without a schema library.

Security

  • Encryption in transit (TLS) complements the engine’s encryption at rest. The first cut speaks plaintext on localhost; TLS is on the near roadmap.
  • The connection layer is the home for auth, roles and per-branch permissions — for example main read-only for some clients, a writable feature branch for others.

Status

The protocol, the client, and the server are in place: CRUD, branch isolation, AS OF, verify, and diff/merge all work over a real socket. Next on the line are multi-statement transactions (with a writer timeout), then TLS with auth and per-branch permissions, and — optionally — a pgwire compatibility layer for generic CRUD.