> For AI agents: the complete documentation index is available at https://docs.flashnerd.com/llms.txt, the full documentation bundle is available at https://docs.flashnerd.com/llms-full.txt.

# Package rules and dependencies

A `.flashnerd` file is an unencrypted ZIP. This page defines its layout and shared record rules; the [format overview](https://docs.flashnerd.com/reference/flashnerd-format/index.md) links to each collection and field definition.

## Layout

Paths start at the **ZIP archive root**. These are example filenames, not mandatory basenames. Every collection and its directory is optional; include the records needed by your references.

```text
Archive root
├── manifest.json                      # Generated on export; ignored on import
├── content/
│   ├── review_folders/
│   │   └── folders.jsonl               # Folders that organize decks
│   ├── decks/
│   │   └── tokyo.jsonl                 # Decks and field definitions
│   ├── tags/
│   │   └── tags.jsonl                  # Reusable tags
│   └── cards/
│       └── notes.jsonl                 # Cards and field values
├── srs/
│   ├── srs_folders/
│   │   └── folders.jsonl               # Folders that organize SRS sets
│   └── srs_sets/
│       └── daily.jsonl                 # SRS sets, settings and linked decks
├── progress/
│   └── schedules/
│       └── current.jsonl               # Current SRS schedules
├── history/
│   ├── srs_reviews/
│   │   └── reviews.jsonl               # SRS review events
│   └── normal_reviews/
│       └── reviews.jsonl               # Flashcard and matching review events
├── preferences/
│   ├── user.json                      # One object of portable preferences
│   ├── card_template_presets/
│   │   └── basic.jsonl                 # Saved question/answer template
│   ├── srs_presets/
│   │   └── daily.jsonl                 # Saved daily study settings
│   ├── ai_instruction_presets/
│   │   └── basic.jsonl                 # Saved AI generation instructions
│   └── search_presets/
│       └── text.jsonl                  # Saved search filters
└── media/
    ├── cat.png                         # Example image bytes
    └── example.wav                     # Example audio bytes
```

See the linked record pages in the [dependency table](#dependencies) for every file location and supported property.

## JSONL and filenames

- Each collection accepts any **direct child** ending exactly in `.jsonl`. For example, `content/cards/basic.jsonl`, `content/cards/daily.jsonl` and `content/cards/00000.jsonl` are equally valid. Export uses numbered filenames by convention.
- A file can contain one or many records of that collection's type. Multiple files in a collection are also allowed; their paths are sorted lexicographically. File order does not create relationships.
- Use UTF-8, with **one complete JSON object per physical line**, no enclosing array and no comments. Completely empty lines are ignored; lines containing only spaces or tabs are invalid. Use `\n` inside a string for a newline in card text. Pretty-printing a record across multiple lines is not accepted.
- `preferences/user.json` has an exact filename and contains **one JSON object**, which can be pretty-printed. It is not JSONL.
- Omit unused files/directories. A package needs at least one valid content or preset record, or one explicitly supplied non-null preference (`false` and `0` count). Empty JSONL files, `{}` or all-null `preferences/user.json`, and manifest-only or media-only archives are not importable. Empty files remain allowed beside meaningful data. Existing syntax, field, and reference errors take precedence.
- Paths are exact. `srs_presets/test.json` and a root `user.json` are ignored; use `preferences/srs_presets/*.jsonl` and `preferences/user.json`. `study/srs_folders` and `study/srs_sets` are unrecognized; use `srs/srs_folders` and `srs/srs_sets`. There is no path repair or JSON reformatting.
- Unrelated members, including manifests and macOS metadata, are skipped when valid importable data exists. Import does not unwrap an enclosing folder: `my-export/content/cards/notes.jsonl` is not recognized.
- Extra JSON properties are ignored in records and nested settings. They are not retained on a later export. Each reference lists the recognized properties; optional does not universally mean nullable.
- Recognized properties still need valid values, and required properties must still be supplied. Extra properties do not repair missing relationships or unknown field IDs in a card's `values` map. Malformed JSON, duplicate keys, invalid enums and invalid references remain errors.
- Settings and values are structured JSON, not JSON encoded a second time inside strings.

## Identifiers and enums

- IDs are opaque strings. Readable keys such as `deck-tokyo` are valid; UUIDs are not required when authoring a package.
- Any JSONL record may omit its own `id`. It receives a temporary source identity, not an ID for later updates. Explicit null, non-string and empty IDs are invalid. Do not construct references to generated identities.
- Relationship IDs remain required and must name explicitly identified companions in the same package, except that scoped cards-only files omit `deckId` and use the caller's destination fields. Deck field IDs remain required. Card-template preset fields may omit `id` unless another field references them; a TTS target must have an explicit ID. Names, filenames and field positions do not resolve references.
- Search-preset `selectedTagIds` and `selectedDeckIds` match exact, explicit IDs in this archive's `content/tags/` and `content/decks/` records. A matching tag label, deck name, or ID already in the destination collection does not satisfy an absent archive reference. The preset may omit its own `id`; selected companions must supply theirs. Omitted or empty selections leave that filter unrestricted. See the [search-preset reference](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#search-presets) for a filter and its companion tag file.
- Omitted preset-field IDs receive temporary source identities and fresh app UUIDs on import. Override Existing preserves supplied field IDs only when the preset itself has an explicit ID; omitted field IDs are regenerated on every import. Updating a saved preset does not change existing deck fields. Exports include concrete field IDs.
- Ordinary app imports remap readable source IDs to stored IDs. Updating an existing card requires its persisted ID, obtainable from an app export. Anonymous cards always create new cards, including with **Override existing** enabled; repeated anonymous history imports create new events. Ordinary copy imports can reuse tags by trimmed, case-insensitive label, so omitted IDs do not guarantee a new tag. With override enabled, a schedule is updated by its referenced card and keeps that local schedule ID.
- A card, folder, deck, tag, set, or schedule needs an explicit ID when another record references it. Anonymous records and explicitly identified companions may coexist in the same package.
- Enums use the exact strings in the [enum catalog](https://docs.flashnerd.com/reference/flashnerd-format/enums.md). The documented exception is SRS `reviewBehavior.noAnswerRating`, which uses integer ratings 1–4.

## Required authoring input

Own IDs stay optional except that referenced records must supply explicit IDs. Names and filenames do not resolve links.

| Collection             | Required keys                                                                                                    |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Review folders         | `name`                                                                                                           |
| Decks                  | `name`, `fields`                                                                                                 |
| Tags                   | `label`                                                                                                          |
| Cards                  | `deckId` in ordinary packages; omit it in scoped cards-only files. Omitted `values` means an empty card.         |
| SRS folders            | `name`                                                                                                           |
| SRS sets               | `name`                                                                                                           |
| Card-template presets  | `name`, `fields`                                                                                                 |
| SRS presets            | `name`                                                                                                           |
| Search presets         | `name`                                                                                                           |
| AI instruction presets | `name`, `instruction`                                                                                            |
| Schedules              | `reviewCardId`, `setId`, `state`, exactly one populated `timeDue` or `dueReviewDay`, plus state-dependent values |
| SRS history            | `srsCardId`, `occurredAtUtc`, `reviewPeriodKey`, `rating`                                                        |
| Normal history         | `cardId`, `deckId`, `occurredAtUtc`, `reviewPeriodKey`, `studyMode`, `isCorrect`                                 |

Still required, with specific purposes:

- Names and labels identify authored content.
- Relationship IDs name the intended companion.
- Field definitions keep explicit `id`, `name`, `side`, and `type`, with valid front/back coverage.
- Card-value `type` stays required for typed parsing against the template.
- History keeps occurrence time and independently assigned review day.
- Normal-history `deckId` stays required because the historical deck may differ from the current card deck.
- Scheduling keeps due time, state, and conditional memory values. New content can omit progress entirely.
- Nested payloads keep required range endpoints, rectangle dimensions, selected TTS references, and learning-step values/units.

General settings, field settings, partial SRS settings, and user preferences already support omission. There is no blanket defaulting pass.

## Timestamps and calendar dates

Timestamps use `YYYY-MM-DDTHH:mm:ss`, optionally followed by fractional seconds, and end in `Z` or `±HH:mm`; for example `2026-01-01T09:00:00+09:00`. Offsets are accepted and normalized to UTC. Writers emit UTC.

The optional fraction has one through six digits. Readers validate real calendar dates, hours `00–23`, minutes/seconds `00–59`, and offset hours/minutes. Missing zones, incomplete times, leap seconds and impossible dates are rejected. Microsecond precision is preserved. Input years and the resulting UTC year must be `0000–9999`.

Calendar dates (`reviewPeriodKey` and search bounds) are zero-padded `YYYY-MM-DD` strings, such as `2026-01-01`, with real dates in years `0001–9999`. Year zero is rejected for calendar dates independently of timestamp validation. They are not timestamps.

`createdAt` and `updatedAt` are independently optional on folders, decks, tags, cards, SRS sets, and preset records that support these timestamps. Omission and explicit `null` mean unavailable metadata. The format does not invent dates from read time, ZIP timestamps, filesystem mtimes, or an epoch placeholder.

When importing an archive through **Home** or **SRS**, new records use supplied dates and fill each missing date independently with the captured UTC commit time. **Override existing** preserves an existing record's creation date and uses the supplied update date or commit time. A copy import that reuses a tag by label keeps that tag's existing dates.

A deck's **Add Card** flow does not restore source card timestamps, whether the input is cards-only or an ordinary archive. New cards receive the commit time for both dates. Matching updates preserve the existing creation date and set the update date to the commit time.

Both history types require `occurredAtUtc` and `reviewPeriodKey`. The review day is independent of the timestamp's UTC date and is preserved without recalculating it from current timezone or rollover preferences. `review_date` cannot replace the required `occurredAtUtc` and `reviewPeriodKey` properties.

## Dependencies

All collection files below use JSONL. Filenames are arbitrary within the listed directory; `*.jsonl` means a direct-child file such as `basic.jsonl` or `00000.jsonl`.

| Archive location                                                                                                                       | Standalone support            | Required or conditional companions                                                                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [preferences/card_template_presets/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#card-template-presets)   | Yes                           | Field definitions are included in the preset. Field-referenced TTS needs an explicitly identified source field within that same preset, not another file type.                                                                                                                      |
| [preferences/srs_presets/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#srs-presets)                       | Yes                           | Settings are included directly. No SRS set, deck, card, or other preset is needed.                                                                                                                                                                                                  |
| [preferences/ai_instruction_presets/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#ai-instruction-presets) | Yes                           | Supply `name` and `instruction`. A deck selecting the preset must include its explicit ID and the preset in the same archive.                                                                                                                                                       |
| [preferences/search_presets/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#search-presets)                 | Conditional                   | Standalone when `selectedDeckIds` and `selectedTagIds` are omitted or empty. Otherwise, include each selected deck/tag and its dependencies.                                                                                                                                        |
| [preferences/user.json](https://docs.flashnerd.com/reference/flashnerd-format/preferences.md)                                          | Yes                           | Supply at least one recognized, non-null preference. Explicit `false` and `0` count; `{}` or only ignored properties do not. This file is one JSON object, not JSONL.                                                                                                               |
| [content/tags/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/folders-and-tags.md#tags)                                | Yes                           | Tags do not require cards or decks.                                                                                                                                                                                                                                                 |
| [content/review_folders/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/folders-and-tags.md#review-folders)            | Yes, with parent records      | Root folders need no companions. A non-null `parentId` requires its parent in this same collection, including any further ancestors. No decks are required.                                                                                                                         |
| [content/decks/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/decks.md)                                               | Conditional                   | A root deck can stand alone without cards. A supplied non-null `folderId` requires a review folder. The deck includes its own field definitions.                                                                                                                                    |
| [content/cards/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/cards.md)                                               | With destination context only | Ordinary `deckId` requires an explicit deck. Scoped cards-only records omit `deckId` and use the selected destination's fields. Each supplied `tagIds` entry still requires an archive tag. Media values may reference files under `media/`; see the missing-media exception below. |
| [srs/srs_folders/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/srs.md#srs-folders)                                   | Yes, with parent records      | Root folders need no companions. A non-null `parentId` requires its parent in this same collection, including any further ancestors. No SRS sets are required.                                                                                                                      |
| [srs/srs_sets/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/srs.md#srs-sets)                                         | Conditional                   | An empty root set can stand alone. Each `deckIds` entry requires a deck. A supplied non-null `folderId` requires an SRS folder. Settings are included in the set.                                                                                                                   |
| [progress/schedules/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md#schedules)                 | No                            | `reviewCardId` requires a card; `setId` requires an SRS set. Include the card's deck, and include that deck in the set's `deckIds`.                                                                                                                                                 |
| [history/srs_reviews/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md#srs-reviews)              | No                            | `srsCardId` refers to an explicit **schedule ID**, not a content-card ID. Include that schedule and its card, deck, SRS set, and other dependencies.                                                                                                                                |
| [history/normal_reviews/\*.jsonl](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md#normal-reviews)        | No                            | `cardId` and `deckId` require explicit card/deck records. Include the card's own deck too if different from the historical `deckId`. No SRS set or schedule is required.                                                                                                            |
| [media/](https://docs.flashnerd.com/reference/flashnerd-format/media.md)                                                               | No standalone import          | Card values reference individual files using exact `mediaPath` values. Unused media alone does not count as importable content.                                                                                                                                                     |
| [manifest.json](#manifest)                                                                                                             | Ignored on import             | No record depends on the manifest. It is export metadata and cannot make an otherwise empty archive importable.                                                                                                                                                                     |

AI instruction presets can stand alone in `preferences/ai_instruction_presets/`. A deck with non-null `aiInstructionPresetId` also requires that explicitly identified preset in the same archive.

### How record references work

- **Include the targets in the same archive.** A matching record already in the destination app does not replace a missing companion, including with Override Existing enabled. The explicit exception is scoped cards-only import: the caller supplies the destination template, and card JSON must omit `deckId`. This does not relax tag references or repair a malformed full archive.
- **Referenced records need explicit IDs.** An unreferenced record may omit its own `id`, but another record cannot target its generated identity. IDs match exactly, including case; names, labels, filenames, and record positions do not substitute for them.
- **Follow every dependency.** If a card needs a deck and that deck has `folderId`, include the folder and its ancestors too. If the card supplies tag IDs, include those tags.
- **File boundaries do not create links.** Put related records of one collection in the same JSONL file or separate files in that collection's directory. The filenames do not have to match across directories, and ZIP member order does not determine relationships.
- **The two folder collections are separate.** Decks use review folders; SRS sets use SRS folders. Each folder's parent must belong to its own collection.

### Presets and internal field links

Decks carry their own `fields`; they do not have to include or reference a card-template preset. SRS sets carry their own `settings`; they do not have to include or reference an SRS preset. Importing one of these reusable presets does not create a deck/set or automatically apply its configuration to existing content.

Within a deck or card-template preset, field-referenced TTS uses `settings.contentSourceId` to identify a field in that same layout. The source must have an explicit field ID and a supported type: text, Chinese, Japanese, or cloze. It cannot reference another deck's field or a separate preset. Manual TTS has no source-field dependency.

Card `values` keys must identify fields in the card's own deck, with matching value types. Deck field IDs are required. Preset field IDs may be omitted when no other field references them. See the [shared field reference](https://docs.flashnerd.com/reference/flashnerd-format/fields.md) for examples and supported settings.

Search presets with filters such as `struggle`, field types, or date bounds do not require matching cards, schedules, or history to be included. Only their explicit deck/tag selections introduce those record dependencies. Omitting a selection or using `[]` means no restriction from that selection, rather than zero matching cards. See the [search-preset companion example](https://docs.flashnerd.com/reference/flashnerd-format/presets.md#search-presets).

### Progress and history restoration

Schedules and both history types are optional for new content. A schedule requires its card and SRS set, and the set must include the card's deck. A card can have only one schedule, and a deck can belong to only one SRS set in the archive.

SRS history depends on schedule records; it does not reconstruct a missing schedule by replaying past reviews. Normal history depends on cards and decks without needing SRS data. Its historical `deckId` may differ from the card's current deck, so include both decks when necessary.

In the app, **Include study progress** defaults to off and controls restoration of schedules and **both SRS and normal review history**. When it is off, those records are not restored. Newly imported cards linked to SRS sets start New when no schedule is restored; overriding existing cards with progress off preserves their existing local progress. Progress/history alone cannot form a usable import; include their content companions even when the destination already has them.

If the app cannot load progress/history but the content is otherwise valid, it can continue with content only and show an **Unable to load study progress** warning. That fallback omits all imported schedules and both history collections, rather than skipping only an individual bad review.

### Media is a recoverable exception

Card media references use an exact archive path such as `media/cat.png`, not a record ID. Image/audio field definitions in decks or template presets do not themselves require media; the dependency begins when a card value supplies `mediaPath`.

Import allows a referenced media file to be missing. The app retains the card with a blank media value and reports missing media; a missing image-occlusion image also removes its rectangles. Unsafe paths and present but empty, oversized, or ZIP-corrupted referenced media still fail validation. Package checks cover ZIP integrity and size; they do not decode image or audio formats.

### Small package combinations

These combinations assume root decks/sets/folders and no optional tag or media references. Include any additional companions named by your actual records.

| What to import                                    | Collections to include                                                                                                                                           |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A saved card template or SRS preset               | Just `preferences/card_template_presets/` or `preferences/srs_presets/`.                                                                                         |
| A saved search filter without deck/tag selections | Just `preferences/search_presets/`.                                                                                                                              |
| A preference such as app theme                    | Just `preferences/user.json` with a supported value.                                                                                                             |
| Ordinary flashcards                               | `content/decks/` + `content/cards/`.                                                                                                                             |
| Cards for an already selected deck                | Just `content/cards/`, with every `deckId` omitted and destination template supplied by the Add Card caller. Tags/media are optional companions when referenced. |
| New SRS study content                             | `content/decks/` + `content/cards/` + `srs/srs_sets/`. Link the decks from the set; imported schedules/history are optional.                                     |
| Flashcard or matching review history              | `content/decks/` + `content/cards/` + `history/normal_reviews/`. Enable Include study progress to restore the events.                                            |
| Current SRS progress                              | `content/decks/` + `content/cards/` + `srs/srs_sets/` + `progress/schedules/`. Enable Include study progress.                                                    |
| SRS progress with review history                  | The current-progress combination above + `history/srs_reviews/`. Enable Include study progress.                                                                  |

## Profiles

Import streams whatever recognized files are present; it does not read the manifest profile.

| Export profile | Typical contents                                                         | Meaning                                                                                             |
| -------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `content`      | Content, media, optional study collections, presets and user preferences | Portable exchange. Exports omit progress/history. Imported cards start New when progress is absent. |
| `backup`       | Content plus schedules and history                                       | Library snapshot. Schedules are authoritative; restore does not replay history to reconstruct them. |

## Archive rules

- Readers accept STORE (method 0) and DEFLATE (method 8). JSON is normally DEFLATE-compressed. Writers compress media only when that makes it smaller.
- Writers emit ZIP32 while counts, sizes and offsets fit; otherwise they emit ZIP64 structures.
- JSONL files have configurable limits of 10,000 records or 64 MiB uncompressed by default. These apply on import too; split larger collections across files.
- Media uses exact `media/<filename>` references, with no base64 or asset catalog. Filenames may contain spaces and Unicode; nested media paths are not supported.
- Streamed members are checked for CRC and actual size. Import does not require SHA-256 hashes.
- Encryption, unsupported compression, symlinks, path traversal, duplicate ZIP names, overlapping members and excessive resource use are rejected.

## Limits

Keep generated files within the app's limits and split large JSONL collections into multiple files. Passing the downloadable schemas does not establish that every app constraint is satisfied.

### App behavior

- A deck holds at most **20,000 cards**, and a card has at most **five distinct tags**. Ordinary archive import retains the first 20,000 cards per source deck and first five distinct tags, with warnings. Add Card rejects an oversized source or a result that would exceed the destination's card limit.
- Review folders and SRS folders allow at most **six nested folder levels**. The collection root is level 0; folders occupy levels 1–6. A seventh nested folder is rejected, even if empty. Schema checks alone do not enforce this app rule.
- The app stores trimmed folder, deck, set, and preset names up to **200 UTF-16 code units**, and field/tag labels up to **100**. Import shortens longer metadata without splitting a grapheme. The default package and schema name limits below are smaller; short authoring names work across both.
- Import accepts larger compressed packages, more cards in an archive, and more input tags than those defaults, and accepts longer metadata before shortening it. Other archive resource protections still apply. Available device storage can also prevent an import; these overrides do not promise unlimited file handling.

### Default schema and package limits

The table lists default package-validation limits. The app applies the behavior described above. The downloadable schemas separately constrain individual records; they do not check ZIP sizes or every package rule.

For string lengths, schema `maxLength` counts **Unicode code points in the supplied value, without trimming**. Package validation counts **UTF-16 code units**, trimming names and labels first but measuring AI instruction text without trimming. A supplementary character such as an emoji counts as one code point and two UTF-16 code units. The schemas use the same numeric bounds for these strings, but the different counting and trimming rules mean their results can differ. Passing a schema does not prove the app will import the file.

| Limit                                   | Default package validation                          |
| --------------------------------------- | --------------------------------------------------- |
| Cards                                   | 100,000                                             |
| Media files                             | 100,000                                             |
| Fields per deck or card-template preset | 20                                                  |
| Tags per card                           | 5                                                   |
| Media file                              | 10 MiB                                              |
| Compressed package                      | 2 GiB                                               |
| Expanded package                        | 4 GiB                                               |
| ZIP entries                             | 250,000                                             |
| ZIP central directory                   | 64 MiB                                              |
| Records per JSONL file                  | 10,000                                              |
| Uncompressed JSONL file                 | 64 MiB                                              |
| JSONL line                              | 2 MiB                                               |
| Folder / deck / set / preset name       | 40 UTF-16 code units, after trimming                |
| Field name                              | 30 UTF-16 code units, after trimming                |
| Tag label                               | 20 UTF-16 code units, after trimming                |
| AI instruction text                     | 10,000 UTF-16 code units, measured without trimming |

## Manifest

The exporter may write `manifest.json` at the ZIP root. **It is not required, and import never reads it**, including its version, profile, feature list, counts, or hashes. A manifest alone cannot make an archive importable. You can omit it when creating or editing a package.

Inspect the <a href="https://docs.flashnerd.com/examples/flashnerd-format/full/manifest.json" download>complete example manifest</a> or its <a href="https://docs.flashnerd.com/examples/flashnerd-format/schemas/manifest.schema.json" download>schema</a>. The following properties describe exported metadata, not required authoring input.

All fields below are emitted by the current writer. They have no omission defaults on import because import ignores the entire file.

| Field              | Type               | Meaning / values                                                                                                      |
| ------------------ | ------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `format`           | string             | Always `flashnerd`.                                                                                                   |
| `version`          | integer            | Export metadata; ignored during import.                                                                               |
| `profile`          | string enum        | `content` or `backup`; see [profiles](https://docs.flashnerd.com/reference/flashnerd-format/package.md).              |
| `packageId`        | string             | Opaque identity of this export.                                                                                       |
| `createdAt`        | timestamp string   | Export creation instant, written in UTC.                                                                              |
| `generator`        | object             | `name` and `version`, both strings identifying the exporting program.                                                 |
| `requiredFeatures` | string array       | Features used by the writer. Current feature strings: `fsrs_decay`, `deflate_media`. Import does not check this list. |
| `counts`           | object of integers | Record totals by collection; keys listed below.                                                                       |
| `shards`           | object array       | Metadata for each JSONL record member; fields listed below.                                                           |
| `sizes`            | object of integers | `compressedBytes`: finished ZIP file length. `uncompressedBytes`: sum of uncompressed members except `manifest.json`. |

#### Count keys

| Key                    | Collection                           |
| ---------------------- | ------------------------------------ |
| `reviewFolders`        | `content/review_folders`             |
| `decks`                | `content/decks`                      |
| `tags`                 | `content/tags`                       |
| `cards`                | `content/cards`                      |
| `srsFolders`           | `srs/srs_folders`                    |
| `srsSets`              | `srs/srs_sets`                       |
| `schedules`            | `progress/schedules`                 |
| `srsReviews`           | `history/srs_reviews`                |
| `normalReviews`        | `history/normal_reviews`             |
| `cardTemplatePresets`  | `preferences/card_template_presets`  |
| `srsPresets`           | `preferences/srs_presets`            |
| `searchPresets`        | `preferences/search_presets`         |
| `aiInstructionPresets` | `preferences/ai_instruction_presets` |

There is no assets count or asset collection. User preferences and media are not JSONL record collections and do not appear in this counts object.

#### Shard entry fields

| Field               | Type    | Meaning                                                      |
| ------------------- | ------- | ------------------------------------------------------------ |
| `path`              | string  | Exact archive member path, e.g. `content/cards/00000.jsonl`. |
| `records`           | integer | Number of records in this JSONL member.                      |
| `sha256`            | string  | Hexadecimal SHA-256 of its uncompressed bytes.               |
| `uncompressedBytes` | integer | Length of its uncompressed bytes.                            |

These hashes are export metadata; import checks ZIP integrity without requiring SHA-256. `preferences/user.json` and media are not included in the shard list.

The exporter adds `fsrs_decay` when schedules or SRS reviews contain non-null decay, and `deflate_media` when it compresses media. Import does not gate on either declaration. A missing historical decay value is not filled during import; app-specific progress handling is described in [progress and history](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md).

If you retain an export manifest after editing payload files, its recorded counts and hashes become stale. Omit it or regenerate it with an exporter. Its SHA-256 values do not replace the ZIP integrity checks.

## Compatibility and validation

History records require `occurredAtUtc` and `reviewPeriodKey`; `review_date` cannot replace these required properties. Schedules require exactly one populated `timeDue` or `dueReviewDay`. Use the documented [schedule and history shapes](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md).

[Validation and examples](https://docs.flashnerd.com/reference/flashnerd-format/validation.md) explains the distinct roles of schemas and the app preview. [Cards-only files](https://docs.flashnerd.com/reference/flashnerd-format/cards-only.md) have a separate destination-template contract.
