Fervion
I built an API-first VCS with a Rust storage authority, Go services, scoped encrypted objects, optimistic ref updates, and crash-aware offline queues. Development is paused; the implemented components are usable locally.
- Focus
- Storage consistency · encryption domains · IPC
- Built with
- Rust · Go · PostgreSQL · S3 / MinIO
- Status
- Paused · local development only
- Ownership
- Personal project
Engineering focus
Fervion explores a version control model where clients and agents share the same storage APIs. The difficult parts are deciding which layer owns consistency, preserving encryption boundaries during deduplication and promotion, and recording offline work without claiming that replay solves conflicts.
- The Rust engine owns immutable objects, snapshots, refs, operation logs, and storage invariants.
- Go services validate and orchestrate requests across an explicit IPC boundary.
- Scoped keys, versioned refs, durable queue records, and resumable promotion state make the failure boundaries explicit.
Architecture
-
One storage authority behind network services
Go handles networking, authentication, validation, and orchestration. It calls a running Rust Object Engine through a Unix-domain socket. IPC separates bounded JSON metadata from raw binary payloads behind explicit length fields, avoiding delimiter scanning and base64 expansion for large objects.
-
Immutable content, conditional mutable refs
Objects and snapshots are content-addressed. Refs name the current position and carry a version token. A write must present the token it read; the engine accepts it and advances the version, or rejects it as stale. Public refs reject rewrites.
-
Separate payload and metadata persistence
Payloads use a filesystem backend locally or S3 / MinIO. In S3 mode, Rust-owned PostgreSQL metadata handles refs, operation logs, and tombstones. Go services use PostgreSQL for their own queue, review, audit, and promotion records.
Engineering challenges
Deduplication must respect encryption domains
Scoped objects use AES-256-GCM under the namespace leaf's working key. Chunk identity includes (scope_leaf_id, chunk_hash, swk_version). I avoid a global chunk-hash lookup because it would cross the boundary between scopes. This gives up cross-scope storage savings to preserve that separation.
Concurrent clients must not silently overwrite refs
A ref update compares the caller's expected version with the current version. Only a matching update advances it; a competing client must refetch after rejection. Filesystem-backed roots retain a single-writer restriction, while S3 mode uses PostgreSQL conditional updates for ref consistency.
A crash must not expose a half-enqueued write
The CLI queue stores the raw body and metadata separately through atomic writes. It writes metadata last as the commit marker, so an interrupted enqueue can leave an orphan body but not a replayable partial record. Replay follows sequence order; removal deletes the marker first. Divergent offline work still requires reconciliation.
Workspaces must not mutate their shared cache
Clean workspace files share read-only hard links to cached content. Editing requires an explicit copy-up into a private writable file. Materialization verifies required objects before writing and can fall back to copying when hard links are unavailable.
Promotion changes keys as well as visibility
Moving content between scopes requires re-encryption under the destination key inside Rust. The Go promotion service records workflow progress in PostgreSQL so work can resume across steps. Review gates constrain public and agent promotion; signature trust, attestation, and transactional hardening remain incomplete.
Tradeoffs and current limits
Fervion is paused, is not production-ready, and has never been used in production. Production identity and secret custody, signature and timestamp verification, promotion attestation, multi-replica deployment, and semantic reconciliation of divergent offline writes remain unfinished.
I deliberately did not base the design on Git. That made integration with GitHub and existing Git tools expensive enough that I stopped before production. The local implementation taught me where storage invariants, service orchestration, and operational guarantees need separate ownership.
Code and documentation
Read the code and the documents behind this explanation.