Implementation specification · v1

Reinstate Encrypted Session Snapshot Format v1

Reinstate v0.1.0-rc.8 stores an age-encrypted JSON manifest and immutable age-encrypted session snapshots. Snapshot plaintext is one compact JSON metadata line, a newline, and one adapter-generated TAR stream whose byte length and SHA-256 digest are authenticated before restore. This is Reinstate’s current internal pre-1.0 format, not an open portability standard.

Published
Last verified
Current release
v0.1.0-rc.8
Release status
pre-1.0 release candidate

Specification status and scope

Envelope schema
1
Manifest schema
1
Snapshot kind
reinstate-session-snapshot
Release described
v0.1.0-rc.8

This page documents the released implementation so reviewers can reason about stored objects and migration risk. It does not freeze the format, promise backward compatibility through v1.0, grant compatibility to another implementation, or claim approval by a standards body. Keep independent backups and read release notes before upgrading pre-1.0 data.

Remote object layout

Objects live below the configured profile storage prefix. New setup normally usesprofiles/<profile UUID>; the prefix remains configuration, so consumers must not infer profile identity from an arbitrary bucket path.

profiles/<profile UUID>/
├── manifest.age
└── snapshots/
    └── <snapshot UUID>.age
  • manifest.age is mutable through conditional writes.
  • Each snapshots/<UUID>.age object is immutable and created only if absent.
  • Both object kinds use application/octet-stream.
  • A failed manifest update can leave an orphaned immutable snapshot; it is not a new head.

Decrypted manifest v1

The manifest ciphertext decrypts directly to one JSON object. It is limited to 4 MiB before parsing and rejected when schema_version is not 1.

FieldCurrent meaning
schema_versionManifest contract version; currently 1.
revisionThe snapshot UUID assigned by the most recent successful head update.
sessionsMap keyed by agent:session_id.
updated_atUTC RFC 3339 time of the successful update.

Every session entry contains agent, session_id,snapshot_id, project_id, and updated_at. Storage ETags and conditional create/update requests provide optimistic concurrency; they are not fields inside the plaintext manifest.

Decrypted snapshot framing

<compact Envelope v1 JSON>\n
<exact adapter TAR bytes>

The first newline terminates metadata. Metadata is limited to 1 MiB. The remaining bytes are the adapter artifact described by the sole files[0] entry; there is no delimiter, base64 layer, ZIP container, or second payload.

Envelope v1 fields

FieldValidation and meaning
schema_versionMust equal 1.
kindMust equal reinstate-session-snapshot.
snapshot_idUUID selected at push and required to match the requested object.
parent_revisionPrevious remote snapshot UUID for the same session, or empty on its first head.
agentCurrent adapter identifier, claude or codex.
adapter_schemaAdapter artifact contract version; RC8 writes 1.
source_agent_versionReserved metadata field; RC8 does not populate it in the current push path.
source_platformDetected source platform identifier.
project_idConfigured canonical project identity, checked against the pull request.
session_idVendor session identity, checked against the pull request.
created_atUTC RFC 3339 snapshot creation time.
filesExactly one logical adapter-artifact descriptor.

The single file descriptor has path, mode, size, andsha256. The path is a validated forward-slash vendor-relative session path; mode is currently 0600. Size and SHA-256 cover the complete TAR payload bytes following the metadata line, not the JSON metadata and not merely the inner JSONL record.

Adapter TAR payload

Both RC8 adapters produce a streamed POSIX TAR containing exactly one transformed JSONL session entry. Claude entries must remain below projects/; Codex entries must remain belowsessions/. The TAR entry name must match the planned archive path, remain relative, end in .jsonl, and pass the adapter's safe-path checks.

Export normalizes only allow-listed structural path fields. Restore expands those fields through destination mappings, may rewrite the structural session ID for an explicit keep-both resolution, backs up an existing destination, writes atomically, and verifies that the native adapter discovers the exact restored path.

Encryption and secret boundary

Both manifest and snapshot plaintext are streamed through the Gofilippo.io/age implementation using an age scrypt passphrase recipient. The passphrase is required for encryption and decryption but is not written into the manifest, envelope, TAR, config file, object key, or remote metadata. Storage credentials stay outside the synchronized objects.

“Encrypted” does not mean the format hides every piece of object-store metadata. A storage operator can still observe bucket/object keys, object sizes, request timing, and update patterns. The security model defines that boundary.

Restore validation sequence

  1. Fetch and authenticate the age ciphertext with the supplied passphrase.
  2. Bound and parse the metadata line.
  3. Require the supported schema, snapshot kind, identity, agent, session, and project.
  4. Require exactly one safe, relative, non-credential artifact path.
  5. Stream at most the declared payload size and verify its exact SHA-256 digest.
  6. Require a supported adapter and a safe one-entry TAR path.
  7. Plan the destination, backup any existing session, and write through a private temporary file.
  8. Rediscover the exact session ID at the exact planned native path.

The default snapshot payload maximum is 32 GiB and each transformed JSONL record is limited to 16 MiB. These are implementation bounds, not recommended session sizes or benchmark claims.

Evolution, inspection, and migration

Unknown envelope or manifest schema versions fail closed today. There is no committed public migration command or third-party conformance suite. A future inspector or migration checker must operate locally, redact user data, distinguish ciphertext metadata from decrypted content, and ship only after fixtures and downgrade/failure behavior are reviewed.

Internal specification, not portability standard.

Publishing the current bytes makes Reinstate inspectable. Calling the format an open portability standard would require a separate public proposal, governance, independent implementations, compatibility fixtures, and version-negotiation rules that do not exist in RC8.

Normative implementation sources