Manifest
Spec: Koder Snapshot manifest format (.kvg)
- *ersion:*0.1 (Draft)
- *racking:*snapshots
RFC001 - *tatus:*Draft
R1 — File format
- Extension:
.kvg(Koder Value Graph). - Encoding: UTF-8, normalized to NFC.
- Top
level shape: TOMLlike sections, squarebracketdelimited. - Signing: trailing
[sig.ed25519]block over canonical bytes(everything before
[sig.ed25519]line, sorted keys per section). - Max size: 10 MB (manifest only; blobs stored separately).
R2 — Required top-level sections
[snapshot]
version = <int> # currently 1
hostname = <string>
created_at = <RFC3339>
koder_user_id = <UUID-string>
parent = <UUID-string|null>
arch = "x86_64"|"aarch64"
encrypted_fields = <string[]>
encryption.recipient = <"user@koder-id">[sig.ed25519] is appended at the bottom — its value field is the base64 Ed25519 signature over the canonical-bytes hash.
R3 — Optional sections
[system], [apps], [repos], [secrets], [files], [skips], [hooks] — all optional. Missing section means "no-op" for restore.
R4 — [system]
[system]
timezone = "America/Sao_Paulo"
locale = "pt_BR.UTF-8"
keyboard = "br"
gpu_driver = "nvidia-595" # null if no proprietary driverRestore applies only if [system] is present AND user opt-in (default OFF — too invasive).
R5 — [apps]
Each manager has a list of explicit installs (NOT deps).
[apps]
apt = ["vim", "git", "curl"]
snap = [
{name="android-studio", channel="stable"},
{name="scrcpy"}
]
flatpak = [{ref="org.gimp.GIMP", origin="flathub"}]
kpkg = ["koder-tools", "koder-jet"]Restore diffs current vs manifest, installs missing, never removes (non-destructive).
R6 — [[repos.entry]]
Each repo is an entry in the array:
[[repos.entry]]
slug = "koder"
url = "https://flow.koder.dev/Koder/koder.git"
path = "~/dev/koder"
branch = "master"
dirty = false # if true: warn at restore
config = "submodules: recursive"For repos without public origin (e.g. local-only branches): URL points to kdrive://users/<u>/snapshots/<sid>/repos/<slug>.bundle.
R7 — [secrets]
Entire block is selectively-encrypted: each value is a base64 crypto_box_seal (libsodium) ciphertext against the user's published X25519 pubkey.
[secrets]
ssh_id_ed25519 = "<base64-ciphertext>"
netrc = "<base64-ciphertext>"
gpg_secring = "<base64-ciphertext>"
rclone_config = "<base64-ciphertext>"
gnome_keyring_export = "<base64-ciphertext>"Decryption requires user's local X25519 privkey, stored in gnome-keyring after first snapshot create. Recovery via BIP-39 12 words if keyring lost.
R8 — [[files.entry]]
Files are stored as tar.zst blobs in the Drive next to the manifest; manifest references by path + sha256.
[[files.entry]]
local_path = "~/Documentos"
blob = "kdrive://users/.../snapshots/<id>/data/Documentos.tar.zst"
sha256 = "<hex>"
size_bytes = 227482624Restore extracts blob at local_path (overwrites with prompt; or --force-overwrite flag).
R9 — [skips]
[skips]
patterns = [
"~/.cache
common/.cache/**"
]Capture skips these. Restore is no-op (skips already excluded from blobs).
R10 — [hooks]
[hooks]
pre_restore = []
post_restore = [
"/k-setup local",
"kpkg install koder-tools",
"ln -sf ~/dev/koder/meta/context ~/.claude"
]Hooks run sequentially with bash -c. Failure logs but continues (warnnotfail, per policies/regression-tests.kmd resilience model).
R11 — Canonical bytes for signing
To produce the bytes signed by [sig.ed25519]:
- Take all sections except
[sig.ed25519]. - Sort sections by name lexicographically.
- Within each section, sort keys lexicographically.
- Serialize to canonical TOML (no extra whitespace,
=separator,newline-terminated).
- UTF-8 encode → bytes.
- SHA-256 → 32 bytes → Ed25519 sign with user's identity privkey.
Test templates
- *1*Canonical serialization round-trip: parse → serialize →
parse → byte-identical
- *2*Sig validation: valid sig accepts; tampered byte rejects
- *3*Cross-arch refuse: manifest x86_64 + host aarch64 → restore
refuses without
--force-cross-arch - *4*Encryption round-trip: encrypt with pubkey, decrypt with
matching privkey, get original
- *5*Wrong privkey: decrypt fails loud
- *6*Section ordering insensitive: same manifest with sections
reordered produces same canonical bytes
- *7*Repos array empty: restore is no-op
- *8*Hook failure: pre_restore[0] returns rc=1 → restore logs
warn but continues with filesecretrepo blocks
- *9*Multi-tenant isolation: User A's manifest references
kdrive://users/<A>/...— restore by User B refuses (404 from Drive)
Status
Draft v0.1. Tied to snapshotsRFC001 ratification.