cli.sgit.ai / Articles / A vault you can carry: one zip holds the whole vault, a public key can seal it, and the round trip already works

A vault you can carry: one zip holds the whole vault, a public key can seal it, and the round trip already works

By Dinis Cruz · 2026-10-21 · published · site v0.2.5

Summary: Reading the pack-mode article, I wanted three things made explicit. First, the two modes side by side, the files that exist in each and the order things happen, which is now a section of that article. Second, my understanding that we mix mutable and immutable files and that this is why the architecture works. The code is more precise than my words were: every object's name says its kind, immutable objects are written once and named by their hash, and the few mutable ones come in two sorts, the shared ones that move only by compare-and-swap and the ones with a single owner. Almost everything in a vault is immutable, so it can be copied, cached or zipped in any shape; only a handful of small files say where the history is. Third, the use case that follows: storage that is good at one big file and bad at thousands of small ones, Google Drive, Dropbox, one large object on S3, for vaults that change rarely or in distinct moments. The whole vault is its bare folder, the objects and those few pointers frozen at one moment, and it fits in one zip. Sealed to someone's public key, the host cannot even tell how many objects are inside. I asked whether that works, and it does today, with commands sgit already ships: a published vault cloned, zipped into one 12.7 MB file of 111 members, sealed to a key in half a second, opened, unzipped elsewhere, and cloned from the folder in 0.48 seconds, with the same files and the same history as a clone from the server. What is missing is one command to make the file, a clone that reads it without unzipping, and a smaller envelope: the seal today is 1.78 times the zip.

zip single-file storage google-drive dropbox s3 pki sealing immutable-objects

A vault in one file. On the left, what goes in: the vault's bare/ folder as it is, 106 encrypted objects and 2 public keys that never change, and 3 small pointers that say where the history is, frozen at the moment the file was made; 111 files, 12.7 MB as one stored zip. On the right, what must stay out: the clone's own local/ folder, which holds its key. Below it, how the file is read back today, and what is not built yet.
A vault in one file. On the left, what goes in: the vault's bare/ folder as it is, 106 encrypted objects and 2 public keys that never change, and 3 small pointers that say where the history is, frozen at the moment the file was made; 111 files, 12.7 MB as one stored zip. On the right, what must stay out: the clone's own local/ folder, which holds its key. Below it, how the file is read back today, and what is not built yet.

In short

Side by side first

The first thing I felt the pack-mode article was missing was the picture of the two modes next to each other: which files exist in each, and what happens, in order, when a push, a pull or a clone runs. That is now a section of A pack per push, and it is where this one starts, because the same picture explains everything below.

Mutable and immutable, at the same time

My understanding was that we mix mutable and immutable files at the same time, that most of the data is immutable and the mutable files can simply be copied on top of each other, and that this is why the architecture works so well. The first two are right, and the code is more precise about the third. Every object a vault stores says in its name what kind it is:

KindIn the nameHow it is writtenIn the vault measured below
Immutableimmonce, named by its hash (a key at random); never changed106 objects and 2 public keys
Mutable, many writersmuwonly by compare-and-swap: a write names the version it replaces and loses if someone else got there firstthe named branch's ref and the branch index, 2 files
Mutable, one writersnwby its one owner, so there is no racea clone branch's ref, 1 file

So the mutable files are not copied over each other freely: the shared ones are moved under a rule that makes two writers safe. But the shape I had in mind holds. Nearly all of a vault is immutable, and an immutable object can live anywhere, be copied any number of times and be packed in any container, because its name is its content and every reader checks it. Only a handful of small files have to be kept straight, and only writing them needs a host that can compare-and-swap. Reading needs nothing at all from the host but the bytes.

What that makes possible: a vault in one file

If the immutable part can be shipped in any shape, and the mutable part is three small files, then the whole vault can be one file. That matters for storage that is good at large files and bad at thousands of small ones: Google Drive, Dropbox, a single large object on S3, a USB stick, an attachment. It suits a vault that does not change much, or changes at distinct moments: a release, a report, an archive of a run, the evidence for an audit, a dataset handed over once.

The structure is not new, it is the vault's own folder:

vault.zip
  bare/data/obj-cas-imm-...      every object reachable from the head (106 here)
  bare/keys/key-rnd-imm-...      the public keys (2)
  bare/refs/ref-pid-muw-...      the named branch's head, frozen
  bare/refs/ref-pid-snw-...      a clone branch's head, frozen
  bare/indexes/idx-pid-muw-...   the branch index, frozen
  (never .sg_vault/local/: that is one clone's private state, with its key)

The objects in bare/data/ are exactly what pack mode calls a snapshot pack. The pointers are what turn a snapshot into a vault you can clone: without them a reader would have the objects and no idea where the history starts. So the answer to "is the zip just the snapshot?" is: the snapshot, plus three small files frozen with it.

Sealed with a public key

The file is already ciphertext: the object names are hashes and the contents are encrypted under the vault's read key. Sealing it to someone's public key adds a second lock with a different purpose. It hides the shape, and it names who can open it.

What the place that stores the vault can see in each shape. Loose on a server: the vault id, the number and sizes of the objects, and who fetches what. One zip on Drive, Dropbox or S3: one file, and the zip's own directory of object ids and sizes. The same zip sealed to a public key: one file and its size, and nothing about what is inside. No host reads a filename, a file or a commit message in any of the three.
What the place that stores the vault can see in each shape. Loose on a server: the vault id, the number and sizes of the objects, and who fetches what. One zip on Drive, Dropbox or S3: one file, and the zip's own directory of object ids and sizes. The same zip sealed to a public key: one file and its size, and nothing about what is inside. No host reads a filename, a file or a commit message in any of the three.

The cost is that a sealed file has to be opened whole. A plain zip can be read one member at a time by Range from a host that serves ranges; a sealed one cannot, until it is opened.

It already works

I asked whether this would work with what sgit has today, and it was tried on a vault whose read key is published on purpose, the newsroom's synthetic-users vault from sgit.ai's catalogue:

The round trip, step by step, with the time each took. 1, clone the vault from the hosted server, 13.7 seconds. 2, zip its bare/ folder, 111 files into one 12.7 MB file. 3, seal it to a public key with sgit pki encrypt, 0.47 seconds, a 22.5 MB envelope. 4, open it with the private key, 0.82 seconds, the same zip byte for byte. 5, unzip it into any folder. 6, clone from that folder with sgit clone --transport local, 0.48 seconds, the same working tree and the same three commits.
The round trip, step by step, with the time each took. 1, clone the vault from the hosted server, 13.7 seconds. 2, zip its bare/ folder, 111 files into one 12.7 MB file. 3, seal it to a public key with sgit pki encrypt, 0.47 seconds, a 22.5 MB envelope. 4, open it with the private key, 0.82 seconds, the same zip byte for byte. 5, unzip it into any folder. 6, clone from that folder with sgit clone --transport local, 0.48 seconds, the same working tree and the same three commits.
Who holds what in the round trip. The file host only ever holds an opaque file; the recipient's private key and the vault's read key are what open it, and neither is ever on the file host.
Who holds what in the round trip. The file host only ever holds an opaque file; the recipient's private key and the vault's read key are what open it, and neither is ever on the file host.

Every step is a command sgit ships or a plain zip. The clone from the folder has the same files as the one from the server and the same three commits, sgit status reads clean, and it took 0.48 seconds against 13.7 from the hosted API, because nothing crossed a network.

What is missing

What this does not claim

If you would like to keep a vault on Drive, Dropbox or one S3 object, or to hand one to someone as a sealed file, write to agent@riskmandate.ai.

Where this comes from

A message of mine on 21 October 2026, written up by cli.sgit.ai's build agent, cli.build, on the same day; the editorial responsibility is mine. The agent ran the round trip in a cloud sandbox with sgit-ai 0.23.0 from PyPI: sgit clone of the newsroom-synthetic-users vault with its published read key (listed in sgit.ai's vault catalogue), a stored zip of .sg_vault/bare/, sgit pki keygen for a throwaway recipient, sgit pki encrypt --recipient, sgit pki decrypt --fingerprint, an unzip, and sgit clone --transport local --base-url <folder>; diff -r compared the two working trees and sgit history log the commits. The three kinds of object are from the CLI's code at 477d328: Enum__Cache_Mutability (snw, muw), Vault__Crypto (obj-cas-imm-, ref-pid-muw-), Vault__Key_Manager (key-rnd-imm-); that a writable clone keeps its vault key in .sg_vault/local/vault_key and a read-only one its read key in clone_mode.json is from the CLI team's coverage map. The envelope ratio is the measured sizes, 22,530,348 bytes against 12,672,752. The pack-mode facts are from the spec. The research topic: How a vault takes writes.

This page as markdown · its source, admin/content/articles/a-vault-you-can-carry.md