> 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.

# Study progress and review history

These records describe existing study state for backup and migration. Do not invent past reviews, success statistics, or scheduler memory for newly generated cards. Omit these directories for new material; Flashnerd initializes newly imported cards linked to a set as New. Overriding an existing collection can retain existing progress; omission is not a reset command. Restoring progress requires the archive import workflow and **Include study progress**, which starts off. See [Back up and restore](https://docs.flashnerd.com/guide/import-export/backups.md).

The comprehensive download contains synthetic schedules and review events to demonstrate every shape. Importing that example with progress enabled adds demonstration history to the collection; it is not evidence of real study. Schedule snapshots are authoritative; the app does not replay the history to reconstruct a schedule. If supported content is valid but progress cannot be converted, the app can report a warning and omit all schedules and both history collections.

The short examples below share these companion records. Save each compact object in its named JSONL file; include all three when using the short schedule or SRS-history examples. Normal-history examples need only the deck and card.

`content/decks/tokyo.jsonl`:

```jsonl
{"id":"deck-tokyo","name":"Tokyo vocabulary","fields":[{"id":"term","name":"Term","side":"front","type":"text"},{"id":"definition","name":"Definition","side":"back","type":"text"}]}
```

`content/cards/tokyo.jsonl`:

```jsonl
{"id":"card-konichiwa","deckId":"deck-tokyo","values":{"term":{"type":"text","value":"こんにちは"},"definition":{"type":"text","value":"Hello"}}}
```

`srs/srs_sets/daily.jsonl`:

```jsonl
{"id":"set-daily","name":"Daily Tokyo","deckIds":["deck-tokyo"]}
```

## Schedules

### Schedule purpose and location

Schedules store the current scheduler state. Save `progress/schedules/*.jsonl`, for example `progress/schedules/current.jsonl`, with one object per line. Any direct-child `.jsonl` filename is accepted. This collection is optional and exported only with the backup profile. Import discovers it without a manifest.

Schedules are authoritative: history is not replayed to reconstruct them. A package creating fresh cards can omit progress and history.

### Schedule basic example

Write this record in the location above:

```jsonl
{"id":"schedule-konichiwa","reviewCardId":"card-konichiwa","setId":"set-daily","state":"review","stability":1,"difficulty":5,"timeDue":"2026-01-02T00:00:00Z","lastReviewTime":"2026-01-01T00:00:00Z"}
```

### Schedule full example

Download the comprehensive example’s <a href="https://docs.flashnerd.com/examples/flashnerd-format/full/progress/schedules/00000.jsonl" download>progress/schedules/00000.jsonl</a>, or read its expanded records below. Each object occupies one physical line in the file; the formatting here is for reading.

These are separate schedules for five different cards, not multiple snapshots for one card. Include their cards, decks, and sets from the [full source tree](https://docs.flashnerd.com/reference/flashnerd-format/validation.md#editable-sources). Each state has different allowed null values; a New record cannot have the populated memory fields shown by Relearn. The initial-learning example uses `card-read-line` from the linked full card file.

#### Relearning with a complete memory snapshot

```json
{
  "id": "srs-null",
  "reviewCardId": "card-null-safety",
  "setId": "set-dart",
  "state": "relearn",
  "step": 1,
  "stability": 1.1,
  "difficulty": 7.4,
  "decay": 0.1542,
  "dueReviewDay": "2026-03-02",
  "scheduledIntervalMs": 86400000,
  "lastReviewTime": "2026-03-02T09:00:00.000000Z",
  "lapses": 2,
  "isStruggle": true,
  "successStreak": 1,
  "suspended": false,
  "disabled": false
}
```

#### New: no memory snapshot

```json
{
  "id": "srs-station",
  "reviewCardId": "card-station",
  "setId": "set-travel",
  "state": "new",
  "step": null,
  "stability": null,
  "difficulty": null,
  "timeDue": "2026-03-01T09:00:00.000000Z",
  "lastReviewTime": null,
  "lapses": 0,
  "isStruggle": false,
  "successStreak": 0,
  "suspended": false,
  "disabled": false
}
```

#### Learning after a review

```json
{
  "id": "srs-ticket",
  "reviewCardId": "card-ticket",
  "setId": "set-travel",
  "state": "learn",
  "step": 0,
  "stability": 0.4,
  "difficulty": 6.2,
  "decay": 0.1542,
  "timeDue": "2026-03-02T09:00:00.000000Z",
  "lastReviewTime": "2026-03-01T09:00:00.000000Z",
  "lapses": 0,
  "isStruggle": false,
  "successStreak": 0,
  "suspended": true,
  "disabled": false
}
```

#### Review: no learning step

```json
{
  "id": "srs-list",
  "reviewCardId": "card-list-literal",
  "setId": "set-dart",
  "state": "review",
  "step": null,
  "stability": 2.5,
  "difficulty": 5.0,
  "decay": 0.1542,
  "timeDue": "2026-03-03T09:00:00.000000Z",
  "scheduledIntervalMs": 86400000,
  "lastReviewTime": "2026-03-02T09:00:00.000000Z",
  "lapses": 0,
  "isStruggle": false,
  "successStreak": 3,
  "suspended": false,
  "disabled": true
}
```

#### Initial learning before a first review

```json
{
  "id": "srs-read-line",
  "reviewCardId": "card-read-line",
  "setId": "set-dart",
  "state": "learn",
  "step": 0,
  "stability": null,
  "difficulty": null,
  "timeDue": "2026-03-03T09:00:00.000000Z",
  "lastReviewTime": null,
  "lapses": 0,
  "isStruggle": false,
  "successStreak": 0,
  "suspended": false,
  "disabled": false
}
```

### Schedule fields

| Field                 | Type                           | Required / omission / null                                                                       | Meaning                                                                                                                                                                                                                                            |
| --------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                  | string                         | Optional; nonempty when supplied                                                                 | Unique schedule ID, separate from the content card ID. Omission creates a temporary source identity; see the import behavior below. `null`, `""`, and non-strings are invalid. SRS history that names this schedule needs an explicit schedule ID. |
| `reviewCardId`        | string                         | Required; null rejected                                                                          | Explicit ID of a content card.                                                                                                                                                                                                                     |
| `setId`               | string                         | Required; null rejected                                                                          | SRS set that owns the card's deck.                                                                                                                                                                                                                 |
| `state`               | string enum                    | Required; null rejected                                                                          | `new`, `learn`, `review`, `relearn`; see constraints below.                                                                                                                                                                                        |
| `step`                | integer or null                | Optional; defaults null                                                                          | Current learning/relearning step index.                                                                                                                                                                                                            |
| `stability`           | finite number or null          | Optional; defaults null                                                                          | FSRS stability, in days. Required in some states below.                                                                                                                                                                                            |
| `difficulty`          | finite number or null          | Optional; defaults null                                                                          | FSRS difficulty. Required in some states below.                                                                                                                                                                                                    |
| `decay`               | positive finite number or null | Optional; defaults null                                                                          | Snapshot's positive FSRS forgetting-curve parameter (`w20`), not its negative exponent.                                                                                                                                                            |
| `timeDue`             | timestamp string or null       | Exactly one due field must be populated; inactive omission/null is accepted and omitted on write | Exact due instant. Required for New cards.                                                                                                                                                                                                         |
| `dueReviewDay`        | `YYYY-MM-DD` date or null      | Exactly one due field must be populated; inactive omission/null is accepted and omitted on write | Due study date, resolved by the app under its current reset and timezone. Must be a real Gregorian date with year 0001–9999. New cards cannot use this representation.                                                                             |
| `scheduledIntervalMs` | positive integer or null       | Optional; omission/null stays null; omitted on write when null                                   | Nominal interval selected by the latest answer. Independent of the actual time between last review and due time.                                                                                                                                   |
| `lastReviewTime`      | timestamp string or null       | Optional; defaults null                                                                          | Last review instant.                                                                                                                                                                                                                               |
| `lapses`              | integer or null                | Optional; omission/null becomes `0`                                                              | Lapse count.                                                                                                                                                                                                                                       |
| `successStreak`       | integer or null                | Optional; omission/null becomes `0`                                                              | Consecutive successes.                                                                                                                                                                                                                             |
| `isStruggle`          | boolean or null                | Optional; omission/null becomes `false`                                                          | Struggle flag.                                                                                                                                                                                                                                     |
| `suspended`           | boolean or null                | Optional; omission/null becomes `false`                                                          | Suspension flag.                                                                                                                                                                                                                                   |
| `disabled`            | boolean or null                | Optional; omission/null becomes `false`                                                          | Disabled flag.                                                                                                                                                                                                                                     |

Extra properties are ignored. Use [timestamp rules](https://docs.flashnerd.com/reference/flashnerd-format/package.md#timestamps-and-calendar-dates). The format does not impose extra numeric ranges on step/counts/stability/difficulty; supply meaningful scheduler values. Missing decay stays unknown and is not filled from current settings.

The two due fields are mutually exclusive. A record with both populated or neither populated is rejected, even when a supplied timestamp could agree with a supplied date. No due value is inferred from another field. Learn, Review, and Relearn accept either due representation; New accepts only a timestamp. Suspension and disabling do not change this contract.

`scheduledIntervalMs` is independent of the due representation: either kind can have an unknown nominal interval. A nominal one-day interval is 86,400,000 milliseconds even when the effective wait until the next reset is shorter. The application resolves `dueReviewDay` using its current study-day reset and timezone; changing either can change the effective instant without changing the stored date. The stored `dueReviewDay` is preserved without a timestamp fallback. The import preview evaluates it using the current review timezone and the reset settings that will apply after import.

#### State constraints

| State     | Required snapshot values                                                   | Values that must be omitted or null                                                                 |
| --------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `new`     | No extra snapshot values                                                   | `step`, `stability`, `difficulty`, `decay`, `dueReviewDay`, `scheduledIntervalMs`, `lastReviewTime` |
| `learn`   | `step`; also `stability` and `difficulty` when `lastReviewTime` is present | None beyond the general field rules                                                                 |
| `review`  | `stability`, `difficulty`                                                  | `step`                                                                                              |
| `relearn` | `step`, `stability`, `difficulty`                                          | None beyond the general field rules                                                                 |

`suspended`, `disabled` and `struggle` are not valid schedule states. Use the boolean flags alongside one of the four phases.

### Schedule relationships and another example

Include the referenced [card](https://docs.flashnerd.com/reference/flashnerd-format/cards.md), its [deck](https://docs.flashnerd.com/reference/flashnerd-format/decks.md), and an [SRS set](https://docs.flashnerd.com/reference/flashnerd-format/srs.md#srs-sets) whose `deckIds` includes that deck. Each card can have only one schedule. Cards, sets, and this schedule need explicit IDs when another record references them. Cards whose own ID was omitted cannot be targets. [SRS history](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md#srs-reviews) refers to this record's `id` through `srsCardId`. With Override Existing, Flashnerd updates the schedule owned by the referenced card and keeps that local schedule ID.

Anonymous schedule for an explicit card. Reimporting it creates a new schedule row unless Override Existing updates the schedule already owned by that card:

```jsonl
{"reviewCardId":"card-konichiwa","setId":"set-daily","state":"new","timeDue":"2026-01-01T00:00:00.000Z"}
```

For a recorded New-state snapshot, replace the basic record with this complete minimal schedule; do not include both records for the same card:

```jsonl
{"id":"schedule-konichiwa","reviewCardId":"card-konichiwa","setId":"set-daily","state":"new","timeDue":"2026-01-01T00:00:00.000Z"}
```

<a href="https://docs.flashnerd.com/examples/flashnerd-format/schemas/schedule.schema.json" download>JSON Schema</a>

## SRS reviews

### SRS review purpose and location

Each record is an SRS answer event. Save `history/srs_reviews/*.jsonl`, for example `history/srs_reviews/reviews.jsonl`, with one object per line. Any direct-child `.jsonl` filename is accepted. This optional collection is exported in backups; import discovers it directly.

### SRS review basic example

Write this record in the location above:

```jsonl
{"id":"srs-review-konichiwa","srsCardId":"schedule-konichiwa","occurredAtUtc":"2026-01-01T00:00:00Z","reviewPeriodKey":"2026-01-01","rating":"good","logType":"native"}
```

### SRS review full example

Download the comprehensive example’s <a href="https://docs.flashnerd.com/examples/flashnerd-format/full/history/srs_reviews/00000.jsonl" download>history/srs_reviews/00000.jsonl</a>, or read its expanded records below. Each object occupies one physical line in the file; the formatting here is for reading.

The two log types share the same record shape. Both examples include all optional snapshot values and link to schedules in the full package. The linked JSONL file also has Hard and Easy native reviews, so its four records show all rating strings. Review history does not replace the authoritative schedule snapshot.

#### Native review with every snapshot field

```json
{
  "id": "srs-rev-native-list",
  "srsCardId": "srs-list",
  "occurredAtUtc": "2026-03-02T09:00:00.000000Z",
  "reviewPeriodKey": "2026-03-02",
  "rating": "good",
  "logType": "native",
  "reviewDurationMs": 1400,
  "stability": 2.5,
  "difficulty": 5.0,
  "decay": 0.1542,
  "srsState": "review",
  "wasSuspended": false,
  "nextReviewIntervalMs": 86400000
}
```

#### Archived review

```json
{
  "id": "srs-rev-archive-ticket",
  "srsCardId": "srs-ticket",
  "occurredAtUtc": "2026-03-01T09:00:00.000000Z",
  "reviewPeriodKey": "2026-03-01",
  "rating": "again",
  "logType": "archive",
  "reviewDurationMs": 1800,
  "stability": 0.4,
  "difficulty": 6.2,
  "decay": 0.1542,
  "srsState": "learn",
  "wasSuspended": true,
  "nextReviewIntervalMs": 60000
}
```

#### Review with a separately assigned review day

This event occurred on March 1 in UTC but belongs to the March 2 review day. Preserve `reviewPeriodKey` as supplied; it is not derived from the UTC date of `occurredAtUtc`.

```json
{
  "id": "srs-rev-native-list-easy",
  "srsCardId": "srs-list",
  "occurredAtUtc": "2026-03-01T20:00:00.000000Z",
  "reviewPeriodKey": "2026-03-02",
  "rating": "easy",
  "logType": "native",
  "reviewDurationMs": 1200,
  "stability": 2.0,
  "difficulty": 5.1,
  "decay": 0.1542,
  "srsState": "review",
  "wasSuspended": false,
  "nextReviewIntervalMs": 86400000
}
```

### SRS review fields

| Field                  | Type                           | Required / omission / null                                              | Meaning                                                                                                                                                                                                           |
| ---------------------- | ------------------------------ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | string                         | Optional; nonempty when supplied                                        | Unique SRS review event ID. Omission creates a temporary source identity. Repeated imports of anonymous history create new events; they do not replace earlier events. `null`, `""`, and non-strings are invalid. |
| `srsCardId`            | string                         | Required; null rejected                                                 | ID of a schedule in `progress/schedules`, not the content card ID.                                                                                                                                                |
| `occurredAtUtc`        | timestamp string               | Required; null rejected                                                 | Actual answer instant; offsets accepted and normalized to UTC.                                                                                                                                                    |
| `reviewPeriodKey`      | date string                    | Required; null rejected                                                 | Assigned review day, exactly `YYYY-MM-DD`, with a year from `0001` through `9999`.                                                                                                                                |
| `rating`               | string enum                    | Required; null rejected                                                 | `again`, `hard`, `good`, `easy`.                                                                                                                                                                                  |
| `logType`              | string enum                    | Optional; omitted values default to `native`. Explicit null is invalid. | `native` for native history or `archive` for archived history.                                                                                                                                                    |
| `reviewDurationMs`     | integer or null                | Optional; defaults null                                                 | Time spent answering, in milliseconds.                                                                                                                                                                            |
| `stability`            | finite number or null          | Optional; defaults null                                                 | Post-review FSRS stability, in days.                                                                                                                                                                              |
| `difficulty`           | finite number or null          | Optional; defaults null                                                 | Post-review FSRS difficulty.                                                                                                                                                                                      |
| `decay`                | positive finite number or null | Optional; defaults null                                                 | Positive FSRS forgetting-curve parameter immediately after this review.                                                                                                                                           |
| `srsState`             | string enum or null            | Optional; defaults null                                                 | State at review start. Use `new`, `learn`, `review`, or `relearn`, or omit it.                                                                                                                                    |
| `wasSuspended`         | boolean or null                | Optional; defaults null                                                 | Suspension status at review time; null means unknown.                                                                                                                                                             |
| `nextReviewIntervalMs` | integer or null                | Optional; defaults null                                                 | Interval after the review, in milliseconds.                                                                                                                                                                       |

Extra properties are ignored. The format does not apply additional numeric bounds to the duration, interval, stability or difficulty fields. Missing historical values stay unknown. The app preserves supplied values but may estimate missing stability from a `nextReviewIntervalMs` of at least one day when `srsState` is omitted or `review`. When the resulting stability is positive and finite, missing decay is filled from the source schedule’s usable decay or the default FSRS decay. These are 90%-target approximations, not a replay of historical scheduling. Missing difficulty remains unknown. Decay does not require a manifest feature declaration on import.

Use only `new`, `learn`, `review`, or `relearn` in historical `srsState`, or omit it. `suspended`, `disabled`, and `struggle` are not importable history states: the app omits all schedules and both review-history collections when it encounters one in retained history. Valid content may still be imported with a warning. Record suspension with `wasSuspended`.

The app imports `native` and `archive` events the same way and exports stored SRS reviews as `native`. That label distinction does not survive an app import/export cycle.

### SRS review relationships and review dates

Include the referenced [schedule](https://docs.flashnerd.com/reference/flashnerd-format/progress-and-history.md#schedules) and its content card, deck and SRS set. The schedule must supply its own `id`. History does not replace the schedule, and it cannot target an anonymous card or anonymous schedule.

Anonymous event against an explicit schedule. Importing the same line again adds another event:

```jsonl
{"srsCardId":"schedule-konichiwa","occurredAtUtc":"2026-01-01T00:00:00Z","reviewPeriodKey":"2026-01-01","rating":"good","logType":"native"}
```

`occurredAtUtc` and `reviewPeriodKey` are independent and required for both `native` and `archive` records. A review near midnight can belong to a different review day because of timezone or rollover preferences. Do not derive the day from the UTC date. See [timestamp and calendar-date rules](https://docs.flashnerd.com/reference/flashnerd-format/package.md#timestamps-and-calendar-dates).

This complete archived event demonstrates a different assigned day and optional fields. It may be added as another line with its distinct event ID:

```jsonl
{"id":"srs-review-earlier","srsCardId":"schedule-konichiwa","occurredAtUtc":"2026-01-01T01:00:00.000Z","reviewPeriodKey":"2025-12-31","rating":"hard","logType":"archive","reviewDurationMs":1800,"stability":2.5,"difficulty":5.0,"decay":0.5,"srsState":"review","wasSuspended":false,"nextReviewIntervalMs":86400000}
```

<a href="https://docs.flashnerd.com/examples/flashnerd-format/schemas/srs_review.schema.json" download>JSON Schema</a>

## Normal reviews

### Normal review purpose and location

These are answer events from flashcard or matching study, outside SRS. Save `history/normal_reviews/*.jsonl`, for example `history/normal_reviews/reviews.jsonl`. Any direct-child `.jsonl` filename is accepted; use one complete object per line. This optional collection is exported in backups.

### Normal review basic example

Write this record in the location above:

```jsonl
{"id":"normal-review-konichiwa","cardId":"card-konichiwa","deckId":"deck-tokyo","occurredAtUtc":"2026-01-01T00:00:00Z","reviewPeriodKey":"2026-01-01","studyMode":"flashcards","isCorrect":true}
```

### Normal review full example

Download the comprehensive example’s <a href="https://docs.flashnerd.com/examples/flashnerd-format/full/history/normal_reviews/00000.jsonl" download>history/normal_reviews/00000.jsonl</a>, or read its expanded records below. Each object occupies one physical line in the file; the formatting here is for reading.

These separate events show both supported modes and both correctness values. Their cards and historical decks are included in the full package. All optional duration and identity fields are populated.

#### Correct flashcard review

```json
{
  "id": "nrev-flashcards-station",
  "cardId": "card-station",
  "deckId": "deck-japanese-travel",
  "occurredAtUtc": "2026-03-02T09:00:00.000000Z",
  "reviewPeriodKey": "2026-03-02",
  "studyMode": "flashcards",
  "isCorrect": true,
  "reviewDurationMs": 900
}
```

#### Incorrect matching review

```json
{
  "id": "nrev-matching-ticket",
  "cardId": "card-ticket",
  "deckId": "deck-japanese-travel",
  "occurredAtUtc": "2026-03-03T09:00:00.000000Z",
  "reviewPeriodKey": "2026-03-03",
  "studyMode": "matching",
  "isCorrect": false,
  "reviewDurationMs": 1600
}
```

### Normal review fields

| Field              | Type             | Required / omission / null       | Meaning                                                                                                                                                                                                              |
| ------------------ | ---------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`               | string           | Optional; nonempty when supplied | Unique normal-review event ID. Omission creates a temporary source identity. Repeated imports of anonymous history create new events; they do not replace earlier events. `null`, `""`, and non-strings are invalid. |
| `cardId`           | string           | Required; null rejected          | Explicit content-card ID.                                                                                                                                                                                            |
| `deckId`           | string           | Required; null rejected          | Content deck ID.                                                                                                                                                                                                     |
| `occurredAtUtc`    | timestamp string | Required; null rejected          | Actual answer instant; offsets accepted and normalized to UTC.                                                                                                                                                       |
| `reviewPeriodKey`  | date string      | Required; null rejected          | Assigned review day, exactly `YYYY-MM-DD`, with a year from `0001` through `9999`.                                                                                                                                   |
| `studyMode`        | string enum      | Required; null rejected          | `flashcards` or `matching`.                                                                                                                                                                                          |
| `isCorrect`        | boolean          | Required; null rejected          | Whether the answer was correct.                                                                                                                                                                                      |
| `reviewDurationMs` | integer or null  | Optional; defaults null          | Answer duration in milliseconds. No extra numeric range is imposed.                                                                                                                                                  |

Extra properties are ignored. Normal reviews do not use SRS ratings, schedule snapshots, or `logType`.

### Normal review relationships and another example

Include the referenced [card](https://docs.flashnerd.com/reference/flashnerd-format/cards.md) and [deck](https://docs.flashnerd.com/reference/flashnerd-format/decks.md). Both must supply their own IDs. An SRS set or schedule is not needed for normal history.

Anonymous event against an explicit card. Importing the same line again adds another event:

```jsonl
{"cardId":"card-konichiwa","deckId":"deck-tokyo","occurredAtUtc":"2026-01-01T00:00:00Z","reviewPeriodKey":"2026-01-01","studyMode":"flashcards","isCorrect":true}
```

The assigned day is independent of the answer's UTC date and is never recalculated on import. Both values are mandatory; see [timestamp and calendar-date rules](https://docs.flashnerd.com/reference/flashnerd-format/package.md#timestamps-and-calendar-dates).

A matching answer can be another line with a distinct event ID:

```jsonl
{"id":"normal-review-matching","cardId":"card-konichiwa","deckId":"deck-tokyo","occurredAtUtc":"2026-01-02T09:00:00.000Z","reviewPeriodKey":"2026-01-02","studyMode":"matching","isCorrect":false,"reviewDurationMs":2400}
```

<a href="https://docs.flashnerd.com/examples/flashnerd-format/schemas/normal_review.schema.json" download>JSON Schema</a>
