aem

A tiny CLI for append-encrypted manifest snapshots.

versionv0.4.2 buildpassing go1.23+ statusbeta licenseMIT

aem takes the file tree you point it at, computes per-file content hashes, seals them into a single append-only manifest, and never overwrites old entries. It is a snapshot tool, not a sync tool: every run adds a row, nothing is ever deleted.

Designed for people who back up a small home server, a notebook, a single project directory — and want to know, years later, that a particular file existed on a particular date, with a particular hash.

Install

# go install
go install codeberg.org/mb/aem/cmd/aem@latest

# or download a release binary
curl -L https://aem.mectest.ru/dl/v0.4.2/aem_linux_amd64.tar.gz | tar xz

Quickstart

# 1. initialise a manifest in the current directory
$ aem init --passphrase-file ~/.aem.key
created .aem/manifest.aem (encrypted, append-only)

# 2. snapshot a directory
$ aem snap ~/photos
scanned 4128 files (12.7 GiB)
appended snapshot 0001 → manifest grew to 184 KiB

# 3. snap again later — only the delta is recorded
$ aem snap ~/photos
+ 24 new files, ~ 6 changed, − 0 missing
appended snapshot 0002 → manifest grew to 191 KiB

# 4. find what existed at a given date
$ aem at 2026-03-14 -- find img_4128.jpg
snapshot 0011 (2026-03-14 02:11 UTC)
img_4128.jpg  sha256:a1c4… size:4.2 MiB  mtime:2026-03-12 21:08
Not a backup tool. aem records that a file existed and what it looked like. It does not store the bytes. Pair it with restic, borg, rclone, or just a tarball — and use aem as the index.

Manifest format

The manifest is a single append-only file (.aem/manifest.aem) — a stream of length-prefixed CBOR records, each encrypted with XChaCha20-Poly1305 under a key derived from your passphrase via Argon2id. Records carry their own MAC, so truncation past any record boundary is detected on read.

fieldtypenotes
iduint64sequence, monotonic
atuint64UTC unix seconds
pathbytesrelative, NFC
hashbytes(32)BLAKE3
sizeuint64file size at snap time
mtimeint64unix nanos

Schema is versioned via a leading magic record. Older versions are read forward-compatibly; new fields are ignored gracefully.

Why "append-encrypted"

Roadmap

FAQ

Is the manifest format stable?

Not yet. Pre-1.0 means I reserve the right to break it. v0.x manifests will remain readable by future versions via the magic record.

What if I lose the passphrase?

The manifest is unrecoverable. The tool refuses to "help" you by being clever about this. Write the passphrase down. Argon2id parameters mean even a state actor takes years per guess for a 6-word diceware phrase.

Where do I report bugs?

The Codeberg repo — link at the bottom of the page.