Introduce three new ALLCAPS.md tracking files: - STATUS.md: living doc of in-flight work and what shipped in v0.5.0 - ROADMAP.md: full roadmap extracted from CLAUDE.md + expanded with all specced work - FORMATS.md: wire-format quick-reference (.enc blobs, params.json, devices.json, etc.) Update CLAUDE.md to replace the single-spec "Design spec" section with a "Planning & design specs" section that instructs checking docs/superpowers/specs/ and docs/superpowers/plans/ before any planning or implementation work. Also add the rule to update STATUS.md after every dev iteration, and replace the stale v0.5.0-in-progress roadmap paragraph with references to the new files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.5 KiB
Relicario Wire Formats
Quick-reference for the load-bearing binary and JSON formats. Check this file before touching serialization, versioning, or storage layout code. Full diagrams and invariants live in the per-crate
ARCHITECTURE.mdfiles.
Encrypted blob (.enc files)
Every encrypted file — manifest.enc, settings.enc, items/<id>.enc, attachments/<item-id>/<aid>.enc — uses the layout produced by relicario_core::crypto::encrypt (crypto.rs):
┌─────────┬────────────────────────┬──────────────────┬──────────────────┐
│ version │ nonce │ ciphertext │ auth tag │
│ 1 byte │ 24 bytes │ N bytes │ 16 bytes │
│ 0x02 │ random per write │ XChaCha20 stream │ Poly1305 MAC │
└─────────┴────────────────────────┴──────────────────┴──────────────────┘
VERSION_BYTE = 0x02(crypto.rs:59). Any blob starting with0x01is rejected withUnsupportedFormatVersion { found: 0x01, expected: 0x02 }.- Minimum valid blob length: 41 bytes (1 + 24 + 0 + 16).
- Nonces are always fresh from
OsRng— no caller-supplied nonces. - Full diagram:
docs/ARCHITECTURE.md§ "Encrypted File Format".
.relicario/params.json
{
"format_version": 2,
"aead": "xchacha20-poly1305",
"salt_path": ".relicario/salt",
"kdf": {
"argon2_m": 65536,
"argon2_t": 3,
"argon2_p": 4
}
}
Parsed via ParamsFile { kdf: KdfParams } in session.rs. The kdf nesting is intentional — format_version, aead, and salt_path co-exist for forward-compat probing. Do not flatten. Production defaults: m=65536 (64 MiB), t=3, p=4. Tests use m=256, t=1, p=1.
.relicario/salt
32 raw bytes. Not secret. Generated once at vault init via OsRng. Feeds Argon2id as the KDF salt.
Manifest (manifest.enc)
Decrypts to JSON matching the Manifest struct (manifest.rs).
- Schema version:
MANIFEST_SCHEMA_VERSION = 2(manifest.rs:12). v1 manifests (pre-typed-items) fail to parse and are not supported. ManifestEntryfields:id,title,tags,favorite,group,icon_hint,modified,trashed_at,attachment_summaries.- The manifest is rebuilt from scratch on every
upsert— it can never drift from the source-of-truth item files. - Supports case-insensitive title/tag search without decrypting any item.
.relicario/devices.json
[
{ "name": "laptop", "public_key": "<hex-encoded ed25519 public key>" }
]
An empty array ([]) puts the pre-receive hook in bootstrap mode (all pushes accepted). Both devices.json and revoked.json must be empty for bootstrap mode to activate — a non-empty revoked.json alone forces strict verification.
.relicario/revoked.json
[
{ "name": "old-laptop", "public_key": "<hex>", "revoked_at": 1746000000 }
]
Commits by public_key at or after revoked_at (Unix seconds) are rejected by the pre-receive hook. Commits before revoked_at remain valid (they were authorized at the time).
Item IDs and Field IDs
| Kind | Length | Entropy | Source |
|---|---|---|---|
ItemId |
16 hex chars | 64 bits | OsRng |
FieldId |
16 hex chars | 64 bits | OsRng |
AttachmentId |
16 hex chars | content-addressed | first 8 bytes of SHA-256(plaintext) |
AttachmentId is content-addressed — identical plaintexts deduplicate in git automatically.
.relbak backup format
A zstd-compressed tar archive containing a bare git clone of the vault. Designed for relicario backup export/restore.
Full spec: docs/superpowers/specs/2026-04-27-relicario-import-export-design.md.
ItemCore JSON (internal)
ItemCore uses #[serde(tag = "type")] — the outer JSON object gets a "type" discriminator key. No *Core struct may have a field named "type" (use "kind" instead — see CardKind, TotpKind).
Full item type inventory: crates/relicario-core/ARCHITECTURE.md § "Module map".
KDF input construction
The password fed to Argon2id is length-prefixed to prevent extension attacks:
u64_be(len(passphrase)) || passphrase_bytes || u64_be(32) || image_secret
NFC-normalized before hashing. Covered in crypto.rs:229-236 and tested in tests/format_v2.rs:44-54.