sgit newsroom v0.1.29 · snapshot 2026-09-24

Reading room · sgit.ai

On this page

Reading room / sgit.ai · raw text · live ↗

From sgit.ai, the page as fetched on 2026-09-24 · open the live page ↗Everything on this sheet is the source site's own text; the newsroom's chrome is outside it.

Git repos inside vaults, SG/Vault

Run git and sgit side by side: the encrypted store in a git remote, the leak-audit boundary, the GitHub round trip, plus a pure-Python git reader preview.

Source: https://sgit.ai/docs/vault/git-and-vaults.html↗ · site v0.6.8 · this file is generated from the same content as the page, so the two cannot drift. Every page on this site has a .md twin; internal links below point at them.


Home↗ / SG/Vault↗ / Git repos inside vaults

Git repos inside vaults

Engineering preview. A git repository is, in the end, just files, which means a vault can hold a complete repo, .git folder included, giving you an end-to-end-encrypted remote for your full history. The missing piece is legibility: making that history readable wherever the vault lands, without assuming a git binary. That piece now exists.

Worked example, including the ending: this website ran exactly this way for 76 releases (one folder, both systems, two pushes per release) and then retired the vault mirror in September 2026 because it had no reader and was 91% of the repository. The case study, including the surprise (the encrypted ref always looks modified to git, because AES-GCM re-encrypts with a fresh IV on every write) and the reasons for stopping, is at one working tree, two remotes↗. The pattern below is still the right one when something actually reads the mirror.

A pure-Python git reader

The sgit project has a working git reader, ~600 lines of implementation in the same Type_Safe style as sgit itself, that reads the .git object store directly: loose objects, packfiles (index v2, including large offsets), delta reconstruction (both OFS and REF deltas), symbolic refs and packed-refs. No git binary, no gitpython, no dulwich, its only dependency is the same type-safety framework sgit already uses.

Verified against sgit's own development repository (900+ commits) during review:

>>> svc = Git_Repo__Reader__Service(repo_path='…/SGit-AI__CLI')
>>> [b.name for b in svc.branches()]
['dev', 'claude/sgit-positioning-proposal…']
>>> svc.head_commit()
HEAD 2e2dd4c · 1 file changed · author + message parsed
>>> len(svc.object_parser.flatten_tree(head.tree_sha))
1161   # every file in HEAD, resolved through packfiles and deltas

Why this matters for vaults

Run git and sgit side by side

The integration runs the other way too: the same folder can be a git repository and an sgit vault at once, git's ecosystem (remotes, pull requests, CI, GitHub Pages) over the working files, sgit's zero-knowledge sync over the same content, and a git remote that doubles as an encrypted mirror of the vault itself.

Why this is safe by construction: the bare/ store is byte-parity with what the sync server holds, and the server is untrusted by design: everything in bare/ is protected by the vault key, not by where it sits. Git exposure of bare/ is therefore equivalent to server exposure, which the zero-knowledge model already accepts. A git remote is just a second untrusted server, one that also gives you distribution, replication and history for free.

The boundary reduces to three rules:

# .gitignore — the whole of it
.sg_vault/local/   # plaintext tier: vault key, push token, unwrapped private keys
.sg_vault/work/    # scratch area — may hold plaintext transiently
*.pem              # defence in depth: no unwrapped key material anywhere, ever

Pair it with a .gitattributes that marks .sg_vault/** as binary -diff -merge: ciphertext has no meaningful line diff, and a textual merge would corrupt it. Everything else is committed, including the plaintext working tree, which is the point: the vault's contents readable, searchable and reviewable on GitHub, with blame, PRs and CI on top. That makes repo visibility a content decision, not a crypto one: bare/ is safe either way; your documents are what you are choosing to expose.

The round trip: edit on GitHub, pull back into the vault

Because the working tree is real files, the flow runs both ways. Edit a file in the GitHub web editor, merge a colleague's pull request, let a CI job rewrite a document, then git pull into the local clone, and sgit sees exactly what changed, the same way it sees your own edits: sgit status reports them, sgit commit records them in the vault's history, sgit push seals them to the server. Two provenance trails, both kept: git records who proposed and reviewed a change; sgit records it landing in the encrypted vault.

Before first publication: audit, then keep the discipline

The .gitignore / .gitattributes pair is reproduced in full on the case study↗. And once the vault is on GitHub, the same repo can serve the app itself: see static hosting on GitHub Pages↗.

What a key rotation does to the mirror

Rotating a vault key (delete-on-remote → rekey → push) re-encrypts every object under a new key, so every content-addressed ID changes and the entire store is replaced. In the git mirror that lands as one large commit, for this site, 336 objects deleted and a fresh set added. Nothing breaks (the .gitattributes binary rule means no diff churn), but two consequences are worth knowing before you rotate:

This section exists because it happened here: the passphrase for this site's own vault was written into a tracked build file (an anti-leak regex that became the leak), reached three public commits, and was caught by the audit above. The key was rotated the same hour and the old vault deleted from the server; the exposed content was this public website. Recorded rather than quietly fixed, see the release history↗.

Status, honestly

← Sub-vaults↗Static hosting →↗


Site index for agents↗ · HTML version↗