# As Lived Archive Contract

Version 1.0 — effective July 28, 2026

Your story should outlive any app. You may entrust As Lived with decades of your life. In return, As Lived makes these durable promises about your archive—not just the app that reads it today.

## 1. Documented export format

An As Lived Files backup is a regular folder. The current archive format uses:

- `manifest.json`: the format identifier, schema version, backup ID, creation date, encryption settings, record counts, file list, and checksum-index fingerprint.
- `checksums.json`: SHA-256 fingerprints for the files stored in the backup.
- `database/memories.jsonl`
- `database/media.jsonl`
- `database/people.jsonl`
- `database/places.jsonl`
- `database/tags.jsonl`
- `database/recaps.jsonl`
- `database/label-corrections.jsonl` in schema version 2 and later.
- `media/<media-id>/metadata.json`: the media identifier, original size and fingerprint, encryption state, and ordered chunk list.
- `media/<media-id>/chunk-xxxxx.bin` for unencrypted media or `chunk-xxxxx.enc` for encrypted media.

The format identifier is `com.storyofme.private.backup`. Database records use JSON Lines: one ordinary JSON object per line. Dates are encoded as milliseconds since 00:00:00 UTC on January 1, 1970. JSON object keys are written in sorted order without escaping slashes. Original media is divided into bounded chunks so large archives can be copied and verified safely.

The current schema version is 2. Schema version 1 remains readable.

## 2. Versioned migrations

Every backup declares its schema version. New As Lived releases will keep readers for released archive versions or provide a documented, tested migration.

A restore validates the manifest, paths, counts, encryption authentication, checksums, and conflicts in a separate staging area before changing the current archive. Migration and restore do not rewrite the selected source backup. If validation fails, the current archive remains unchanged.

## 3. Forward compatibility policy

Newer As Lived releases will continue reading older released archive versions. We will add optional fields when practical. A change that cannot remain compatible receives a new schema version and a migration path.

An older release will not silently guess at a newer, unknown schema. It will stop and identify the unsupported version instead of discarding fields it does not understand. Keep the original backup unchanged and use a compatible reader or the published recovery specification.

## 4. If As Lived is discontinued

For a planned discontinuation, As Lived will:

1. Give as much notice as reasonably possible.
2. Keep the final release able to read existing archives and create user-controlled exports.
3. Publish the archive format notes and recovery instructions for independent use.
4. Avoid adding a subscription or account requirement to read, export, or make a safety backup of existing memories.

The exported archive lives in the Files location you chose. That independent copy does not depend on a As Lived account or developer-operated server, even if you later use a hosted As Lived archive. Removing the current app can still delete its private on-device archive, so keep a verified Files backup outside the app.

## 5. Recovering without As Lived

### Unencrypted backup

1. Make a duplicate of the backup folder and work from the duplicate.
2. Confirm that `manifest.json` identifies `com.storyofme.private.backup` and note its `schemaVersion`.
3. Read the `database/*.jsonl` files with any UTF-8 text or JSON Lines tool. Each line is one record.
4. For each item in `database/media.jsonl`, find the matching `media/<media-id>/metadata.json`.
5. Sort that media item's chunks by the numeric `index` in its metadata. Join the chunk files in that order, without separators, to reconstruct the original file.
6. Confirm that the reconstructed file's SHA-256 fingerprint matches `originalSHA256` and that its size matches `originalByteCount`.
7. Use the record's media type and original filename, when present, to choose a suitable filename extension.

### Encrypted backup

An encrypted backup cannot be recovered without its passphrase. As Lived does not store the passphrase and cannot reset it.

The manifest documents the salt, iteration count, and key length. The content key is derived with PBKDF2-HMAC-SHA256. Protected files and media chunks use AES-256-GCM with unique nonces, authentication tags, and path-specific authenticated context. The manifest uses an HMAC-SHA256 authentication key derived from the same master key with HKDF-SHA256. A compatible independent recovery tool must implement those documented contexts exactly and verify every authentication tag and checksum before returning content.

### Encryption interoperability details

- Derive the 32-byte master content key from the UTF-8 passphrase with PBKDF2-HMAC-SHA256, using the Base64-decoded `saltBase64` and the `iterations` value in the manifest.
- Derive the 32-byte manifest authentication key with HKDF-SHA256 from the master key, using the same salt and the UTF-8 info string `storyofme-backup-manifest-auth-v1`.
- Protected database, checksum, and media-metadata files are JSON AES-256-GCM envelopes. Their additional authenticated data is the UTF-8 string `storyofme-backup-file-v1|<lowercase-backup-uuid>|<relative-path>|<original-byte-length>`.
- Encrypted media chunks store ciphertext directly. Their nonce and authentication tag are in `metadata.json`. Their additional authenticated data is the UTF-8 string `storyofme-backup-chunk-v1|<lowercase-backup-uuid>|<lowercase-media-uuid>|<zero-based-chunk-index>|<original-byte-length>`.
- To verify the manifest HMAC, make a copy of the decoded manifest with `authenticationAlgorithm` and `authenticationTagBase64` omitted, encode it using the canonical JSON rules above, and verify the Base64-decoded tag with HMAC-SHA256 and the manifest authentication key.
- After decryption, verify every plaintext length and SHA-256 value before joining or returning files.

## 6. Checksums in plain language

A SHA-256 checksum is a long fingerprint calculated from a file's contents. As Lived records that fingerprint when it creates a backup. During verification or restore, it calculates the fingerprint again.

- If the two fingerprints match, the file arrived exactly as it was saved.
- If they differ, the file may be incomplete or changed. As Lived stops before changing the current archive.
- A checksum detects accidental change; it does not hide a file. Use an encrypted backup when confidentiality matters.

Keep this contract with a backup so the format, promises, and first recovery steps travel with your story.
