# Cosimo

Cosimo is a spaced-repetition system for learning prompt/response pairs with a
screen-reader-accessible desktop interface. Accessibility is a hard project
requirement, not a later polish step.

The current application uses `wxdragon` on top of wxWidgets for the GUI,
stores editable learning content in a plain-text deck file, and stores review
history in SQLite.

## Project Goals

- Make the full review flow usable with screen readers and keyboard input.
- Keep learning content human-editable without pushing users through a database
  editor.
- Keep review history, ratings, and scheduling state separate from the editable
  deck content.
- Favour native controls and platform accessibility APIs over custom-drawn UI.

## Current State

The repository currently contains:

- a deck format for prompt/response pairs
- a typed Rust data model for review ratings
- SQLite-backed review event storage
- scheduled review sessions with configurable minimum session size
- a wxdragon desktop review UI for a single deck file
- pre-cycle deck review with a prompt list on the start screen
- ready-list filtering, including duplicate prompt/response filters,
  problem-card and direction-asymmetry filters, multiple sort criteria, sort
  direction, and per-card details
- card management from the GUI: add, batch add, edit, remove, flag, defer,
  suspend, and mark non-reversible
- reversible cards with independent reverse-direction review history and
  scheduling
- deck format v2 metadata, deck properties, editable deck properties, and
  deck-stored non-reversible markers
- a learning dashboard with a concise summary, recall distribution,
  diagnostics, workload forecasts, study activity, and standard/reverse
  comparison when a deck contains reverse cards
- report-only exam mode with random active-card sampling, optional time limits,
  exact or adjudicated grading, summaries, and saved exam reports
- report-only quiz mode with random active-card sampling, configurable study
  direction, four-choice questions, delayed feedback, answer review, optional
  quiz audio, and saved reports
- optional Opus or legacy WAV audio for ordinary review, ready-list preview,
  exam question prompts, exam grading/review, and quiz sessions
- a Windows `voice.exe` helper for generating review audio as Opus by default,
  or WAV when selected, from installed OneCore or SAPI voices
- snapshot deck sync through a Cosimo sync server, with
  Mastodon-compatible login, owner study-history upload/download, public or
  unlisted content-only downloads, and remote deck deletion by the owner
- recent-deck reopening from `File -> Recent Decks`
- automatic deck, review-database, and full-deck bundle backup options
- language selection for English, Spanish, and Galician
- end-of-session statistics and saved text reports
- flagged-card review, deferral, suspension, and non-reversible card markers
- optional sound notifications and minimise-to-system-tray behaviour

## Licence

Cosimo is released under the GNU General Public Licence version 3. See
[LICENSE](LICENSE).

## Review Model

For a user-facing introduction to studying with Cosimo, see
[docs/user-guide.md](docs/user-guide.md).

Release notes are kept in [CHANGELOG.md](CHANGELOG.md).

Each datum contains:

- a prompt or question
- a response or answer

User-facing documentation uses these terms:

- `study session`: one run from Start, Force Start, or Study Flagged through to
  the summary
- `question`: one prompt presentation inside a study session
- `attempt`: one stored answer with recall feedback and optional confidence
  rating
- `study item`: one schedulable direction of a card, either the standard
  direction or a generated reverse direction

Established phrases such as `review database`, `review history`, `scheduled
review`, and `review audio` still use review for the broader spaced-repetition
process and stored study history.

Before seeing the response, the user may record a guess:

- `1` Don't know
- `2` Probably don't know
- `3` Probably know
- `4` Certainly know
- Space / `Reveal Response` records no guess and stores `Not answered`

After seeing the response, the user records feedback:

- `1` Again
- `2` Hard
- `3` Good
- `4` Easy

The review UI also supports:

- `0` End this session now
- `e` Edit the current card after its response has been revealed
- `Ctrl-F` Flag or unflag the current card during review
- `Ctrl-D` Defer the current card until tomorrow before revealing the response
- `Ctrl-P` Play or stop prompt/response audio when review audio is available;
  on the ready list this previews the selected card's prompt and response

Before a study session starts, Cosimo shows:

- the number of cards that would be scheduled now
- the configured minimum cards per session
- a navigable list of cards labelled by prompt
- a text filter for narrowing the prompt list by prompt or response
- `Add Card`, `Edit Selected`, and `Remove Selected` controls
- `Alt-S` to start the scheduled study session
- `Alt-X` to start an exam session
- `Alt-Z` to start a quiz session
- `Alt-L` to move to the text filter
- `F5` to refresh the ready summary, ready-list filters, and status bar
- `Ctrl-F` to flag or unflag the selected card
- `Alt-T` to force-start a full-deck study session in random order
- `Alt-Q` to quit from the ready screen in English, or `Alt-S` in Spanish and
  Galician

The normal `Add Card` dialogue can mark a new card as non-reversible while it
is created. Batch add deliberately omits that checkbox so repeated entry stays
quick.

Cards can be marked reversible before a study session starts. A generated reverse card
asks for the original response and expects the original prompt, using separate
review history and scheduling state from its parent card. Cosimo blocks reverse
generation when another card with the same response already has an active
generated reverse card, because the reverse prompt would be ambiguous. Duplicate
responses are otherwise allowed. The ready-list duplicate-response filter helps
find those cards before using bulk reversal, and `Deck -> Undo Last Bulk
Reversal` can remove the reverse cards created by the latest bulk batch while
leaving manual reverse cards and review history in place.

The ready summary, ready-list filters, and status bar refresh about once per
minute while the ready screen is open, so newly due cards become available for
scheduled start without reopening the deck.

At the end of a study session, or when the session is ended early, Cosimo shows
a summary dialogue for that session. The dialogue reports counts, percentages,
and timing, then offers `Continue` to return to the ready screen and
`Save Report` to save the summary under `reports/`.

## Scheduling

Normal `Start` builds a scheduled review queue:

- due cards are reviewed first
- if fewer cards are due than the configured minimum cards per session, Cosimo
  randomly fills the queue from the remaining cards
- if the minimum is `0`, only due cards are scheduled

Cosimo uses an FSRS-6 spaced-repetition scheduler. It stores per-card memory
state in the review database, including difficulty, stability, due date,
repetitions, and scheduled lapses. Missed or wrong answers move a card back
toward learning; correct answers increase stability and make later intervals
longer. A lapse means `Again` on a card that had already reached review state,
not every `Again` answer while a card is still being learned. Existing schedule
rows from older beta versions are migrated by replaying stored review history
with the current FSRS-6 scheduler when the review database is opened.

The recall buttons are state-dependent scheduling inputs. In learning and
relearning, they mostly control short steps and graduation back to review; in
review state, they control the next spaced interval, with `Again` moving the
card into relearning. The user guide gives the detailed state-by-state meaning.

For review-state cards, longer intervals are varied slightly and
deterministically to avoid several cards repeatedly coming due on exactly the
same day. Short learning and relearning steps are not varied.

`Force Start` ignores due status and builds a randomised queue containing all
cards that are not suspended or deferred. This gives the user a way to study
even when no cards are due, while still respecting cards the user has
explicitly set aside.
Suspended cards are marked in the ready list, can be toggled from the Card
menu, the ready-list context menu, or Ctrl+S while the ready list has focus,
and are ignored by the status bar when it reports the next due review.
Flagged cards are also marked in the ready list and can be shown with the
flagged-card filter, but flags do not affect scheduling. Flagging is available
from Ctrl-F, the Card menu, the ready-list context menu, and review buttons
after the confidence or recall ratings.
The Card menu can also flag, unflag, suspend, or unsuspend all cards currently
shown in the ready list, which is useful after choosing a filter such as
Problem cards.
`Study Flagged` starts an unscheduled study session through flagged cards that are not
suspended or deferred. Deferral is also available from the ready list and
during the prompt phase of a session before the answer has been revealed.

The minimum cards per session, automatic deck-backup policy, review database
backup policy, sound notifications, review audio, learning-dashboard
calibration rule, and minimise-to-tray behaviour are set in `Tools -> Options`
and are persisted in `cosimo.ini`.

## Repository Layout

For a fuller map of the codebase, see [architecture.md](architecture.md).

- [src/model.rs](src/model.rs): datum, rating, and review types
- [src/deck_format.rs](src/deck_format.rs): human-editable deck parser and formatter
- [src/review_store.rs](src/review_store.rs): SQLite review storage
- [src/scheduler.rs](src/scheduler.rs): due-card scheduling and minimum-session fill
- [src/exam_mode.rs](src/exam_mode.rs): report-only exam setup, answer
  collection, grading, and summaries
- [src/review_audio.rs](src/review_audio.rs): Opus/WAV sidecar audio resolution
  and playback state
- [src/sync.rs](src/sync.rs), [src/sync_http.rs](src/sync_http.rs), and
  [src/sync_http_client.rs](src/sync_http_client.rs): sync storage, HTTP
  routing, and client protocol
- [src/sync_oauth.rs](src/sync_oauth.rs): Mastodon-compatible sync login,
  account verification, and temporary Fediverse token revocation
- [src/localization.rs](src/localization.rs): message catalogue and locale selection
- [src/main.rs](src/main.rs): wxdragon startup and event wiring
- [src/app_state.rs](src/app_state.rs): loaded-deck state and state mutations
- [src/ready_screen.rs](src/ready_screen.rs): main screen rendering,
  ready-list synchronisation, refresh, and menu state
- [src/resident_tray.rs](src/resident_tray.rs): minimise-to-system-tray lifecycle
- [decks/deck.cosimo-deck](decks/deck.cosimo-deck): default deck file used by the GUI
- [ui/main.xrc](ui/main.xrc): main review window
- [ui/card_editor_dialog.xrc](ui/card_editor_dialog.xrc): add/edit card dialogue
- [ui/options_dialog.xrc](ui/options_dialog.xrc): language and session options
- [ui/stats_dialog.xrc](ui/stats_dialog.xrc): study-session statistics dialogue

User-facing documentation lives in [docs/user-guide.md](docs/user-guide.md),
[docs/troubleshooting.md](docs/troubleshooting.md), and
[docs/sync-deployment.md](docs/sync-deployment.md) for running a sync server.

## Deck Format

Cosimo uses a plain-text deck format designed to stay editable by hand.

Example:

```text
deck_version=2
title=Spanish capitals
author=Example author
:::

Capital of Spain
---
Madrid
=1=

Translate this sentence:
I opened the window.
---
Abri la ventana.
=2=
```

Rules:

- current decks begin with a v2 metadata header ending in `:::`
- `---` separates prompt from response
- `=number=` ends one card and stores its stable card identity
- `=numberi=` marks a card as non-reversible
- when adding new cards by hand, use `===` instead of choosing a number; Cosimo
  will assign a safe unused ID when it next opens the deck
- `Deck -> Deck Properties` shows deck metadata, and
  `Deck -> Edit Deck Metadata` can edit the standard metadata fields
- a same-stem directory beside the deck file can contain optional Opus or WAV
  review audio keyed by card ID, such as `1.prompt.opus` and
  `1.response.opus`; these sidecar files are included only in full-deck
  bundle exports/backups, not in automatic deck-content or review-database
  backups
- legacy `===` terminators are accepted and upgraded automatically when the app
  opens the deck
- prompts and responses may span multiple lines
- prompts should be unique; Cosimo refuses normal add and edit actions that
  would create duplicate prompts, and `Deck -> Resolve Duplicate Prompts` can
  repair duplicate prompts introduced by manual deck edits
- duplicate responses are allowed, but from each group of cards with the same
  response, at most one card may have an active generated reverse card
- editing prompt or response text preserves the numbered identity
- keep existing numbered markers when editing existing cards by hand, so review
  history remains attached to the same card
- review history does not live in the deck file

Generated reverse cards reuse the parent card's audio with prompt and response
swapped. Ordinary review can use prompt and response audio, including optional
guiding tones for automatic playback and a ready-list preview command. Exam
mode can use prompt audio while the learner is answering questions, and can
optionally play prompt audio, response audio, or both during grading and answer
review.
`voice.exe` can use OneCore or SAPI voices. Deck metadata can store
`prompt_voice`, `response_voice`, `prompt_voice_engine`, and
`response_voice_engine` defaults for `voice.exe`; command-line voice and engine
options override those defaults. `Deck -> Edit Deck Metadata` lists voices from
`voice.exe` when available, but the fields remain editable for manual filters.
The helper maintains `audio-manifest.tsv` in the sidecar audio directory so it
can skip already tracked files. Generation is conservative: manifest-tracked
files are treated as Cosimo-managed and may be regenerated or converted to the
selected format, while existing untracked `.opus` or legacy `.wav` files are
left untouched as user-owned recordings. The generate audio command on the
Tools menu starts the helper for the current deck when prompt and response
voice metadata are present and generation is allowed, shows progress, and
writes its command output to the `reports` directory. The Tools menu can also
remove inoperative Cosimo audio files for removed card IDs or lower-priority
formats hidden by a preferred playable file. If the generate audio menu item is
disabled, choose prompt/response voices and engines in
`Deck -> Edit Deck Metadata`, and check whether the deck is marked as manual
audio. If you keep your own recordings, use the manual-audio checkbox in
`Deck -> Edit Deck Metadata` to write `audio_generation=disabled`, and back up
the sidecar directory yourself or with a full-deck bundle backup; tracked files
can be overwritten after card text or voice-selection changes when generation
is allowed.

## Runtime Files

- `decks/`: default portable deck directory beside the application
- `decks/deck.cosimo-deck`: default editable learning content
- `decks/deck.reviews.sqlite3`: review history and scheduling database for the default deck
- `decks/deck/` or another same-stem directory: optional Opus or WAV review audio for
  that deck, when present; full-deck bundle exports/backups include these
  files, but automatic deck-content and review-database backups do not
- `voice.exe`: optional Windows helper for generating sidecar Opus or WAV
  files from installed OneCore or SAPI voices
- `reports/`: saved review, exam, and learning-dashboard reports
- `cosimo.ini`: persisted application settings, the most recently opened deck
  path, and the recent-decks list

These default runtime paths are resolved relative to the application executable,
not the shell or shortcut working directory. If the default deck is missing,
Cosimo creates an empty one on startup.

Older beta builds used `cosimo-settings.txt` and `cosimo-last-open-deck.txt`.
When Cosimo finds either file, it migrates their contents into `cosimo.ini` and
then removes the old file.

SQLite review databases are runtime state and are ignored by Fossil.

## Backup and Recovery

Back up each `.cosimo-deck` file, its matching `.reviews.sqlite3` file, and its
same-stem audio directory if you use review audio. The deck file contains the
editable prompts and responses. The review database contains scheduling state,
ratings, and review history. The audio directory contains Opus or WAV recordings and
the generated-audio manifest.

Cosimo also keeps automatic deck-content backups. Before it overwrites an
existing deck file, it copies the current version into the app-level `backups`
directory beside the executable. Backup names use a global rising number and
the deck name, such as `backups/000001-deck.cosimo-deck`. The
`backups/index.txt` file records each backup filename and the original deck
path. These automatic backups protect card text from accidental edits or
migration mistakes, but they do not include review history or sidecar audio.
For a portable copy of a deck and its sidecar files, use `File -> Export Full
Deck`. This writes a zip archive containing the `.cosimo-deck` file and its
same-stem sidecar directory, including audio and the generated-audio manifest,
but not the review database. `File -> Export Full Deck with Study History`
adds a consistent review-database snapshot for personal migration or a complete
manual backup. That archive contains personal study data, so use the no-history
export for sharing deck content. `File -> Full Deck Backup` writes the
deck-and-sidecar bundle into `backups/` with a timestamped name and records it
in `backups/deck-bundle-index.txt`.

`File -> Restore Full Deck` validates one of these bundles, previews its card,
audio, file, and study-history counts, and restores it into the `decks`
directory. If existing files would be overwritten, Cosimo warns first and writes
a full compressed backup of the existing target deck. Restoring a bundle can
still lose newer data if it overwrites newer card text, sidecar audio, manifest,
or review-database files.

The deck backup option in `Tools -> Options` controls automatic deck-content
backups:

- `Full`: keep every automatic deck backup.
- `Last only`: keep only the newest automatic backup for each original deck
  path.
- `None`: do not create automatic deck backups.

The review database backup option controls whether Cosimo keeps one automatic
review-database backup per review database. When set to `On session start`,
Cosimo refreshes that retained backup in the app-level `backups` directory when
a study session starts. The database backup index is
`backups/review-db-index.txt`. When set to `Off`, Cosimo does not create or
refresh review-database backups. Bulk reversible-card creation is also treated
as a significant database change: when review-database backups are enabled,
Cosimo refreshes the retained backup before writing and warns that the retained
backup will be overwritten.

The automatic full deck backup option is separate from both of those. When set
to `Daily`, Cosimo keeps one retained compressed bundle per deck path, refreshed
at most once every 24 hours when the program starts or opens a deck. This
full-deck backup includes the deck file, same-stem sidecar directory, and a
review-database snapshot.

`Tools -> Reclaim Database Space` runs SQLite `VACUUM` on the review database
without deleting dormant review data and without overwriting the retained
review-database backup.

For the default deck, back up:

- `decks/deck.cosimo-deck`
- `decks/deck.reviews.sqlite3`, if it exists
- `decks/deck/`, if you use review audio

For another deck such as `spanish.cosimo-deck`, back up the neighbouring
`spanish.reviews.sqlite3` file and any same-stem sidecar audio directory as
well. Close Cosimo before copying or restoring these files so SQLite is not in
the middle of a write.

Restoring only the `.cosimo-deck` file restores the cards but loses scheduling
history. Restoring both files preserves the cards and their review history.
The optional `cosimo.ini` file can also be backed up to preserve language,
session settings, backup policy, the last opened deck, and the recent-decks
list.

When Cosimo opens a review database, it runs SQLite's quick integrity check
before applying schema setup or deck migrations. It also checks higher-level
consistency after opening, including stored rating and schedule values,
study-session links, and active reversible cards whose responses have become
ambiguous. Duplicate prompts introduced by manual deck edits are reported as a
deck warning rather than a database failure; use the duplicate prompt filter or
`Deck -> Resolve Duplicate Prompts` to repair them. If either database check
fails, close Cosimo and restore the matching `.reviews.sqlite3` file from an
external backup, or fix the active deck if the error is caused by multiple
active reversed cards in the same duplicated-response set.

To restore an automatic deck backup, close Cosimo and copy the chosen backup
over the active `.cosimo-deck` file. If you also need to recover scheduling
history, restore the matching `.reviews.sqlite3` file from an external backup
or from Cosimo's retained review-database backup.

Use `Tools -> Options -> Delete Old Backups` to keep only the newest numbered
deck backup and the newest automatic full-deck backup for each original deck
path. Cosimo asks for confirmation before deleting or renumbering backup files.

## Localisation

The current message catalogue supports English, Spanish, and Galician. Runtime
messages and most control labels go through the localisation layer in
[src/localization.rs](src/localization.rs).

Language is chosen in this order:

- `COSIMO_LANGUAGE`, when set to a recognised code
- the persisted language in `cosimo.ini`
- the system locale
- English

`en`, `en-US`, and similar English codes resolve to English. `es`, `es-ES`,
`es-MX`, and similar Spanish codes resolve to Spanish. `gl`, `gl-ES`, and
similar Galician codes resolve to Galician. Unknown codes fall back to English.
On Windows, Cosimo reads the user's default locale through the platform locale
API. On other platforms, it checks `LC_ALL`, `LC_MESSAGES`, `LANG`, and
`LANGUAGE`.

## Build

The default build artifact is the GUI application.

```bash
cargo build
```

wxdragon and native wxWidgets pieces can take time to compile the first time.
Avoid `cargo clean` unless you actually need to throw away cached build output.

## Test

Fast library-only tests:

```bash
cargo test --lib --no-default-features
```

Check the GUI binary:

```bash
cargo check --bin cosimo
```

Release preparation should also exercise the Windows audio helper and release
package metadata:

```bash
cargo test --bin voice
cargo check --no-default-features --features release-tool --bin cosimo-release
cargo package --locked --offline --allow-dirty
```

Fossil also runs pre-commit verification through
[tools/pre-commit-check.sh](tools/pre-commit-check.sh),
which executes both test commands before a normal commit.

## Run

```bash
cargo run
```

The application defaults to `decks/deck.cosimo-deck` beside the executable.
Review history is stored beside each deck, using the deck stem plus
`.reviews.sqlite3`; for example, `decks/spanish.cosimo-deck` uses
`decks/spanish.reviews.sqlite3`.

## Review Flow

1. On startup, review the ready-screen summary and the list of card prompts.
2. Add, edit, or remove cards before starting the session.
3. Start the scheduled session with `Alt-S`, or force-start the whole deck with
   `Alt-T`.
4. For each prompt, enter `1` through `4` for the pre-response guess, or press
   Space to reveal the response without recording a guess.
5. After the response is shown, enter `1` through `4` for recall feedback. If
   the card text needs correction, press `e` to edit it before rating recall.
6. Enter `0` during either rating phase to end the session early.
7. Review the statistics and continue back to the ready screen.

Exam mode is started separately with `Alt-X` or `Start Exam`. It samples active
cards randomly, excludes suspended and deferred cards, collects typed answers,
and produces a report-only summary. It can also run with a simple minute-based
time limit; the current answer is submitted when time expires, then Cosimo
pauses on a time-out notice before moving to grading, answer review, or the
summary. Exam mode does not record review events or update schedules.

## Accessibility Notes

The current review flow is built around native text and button controls:

- the ready screen exposes the card set through a native list box
- the ready screen supports keyboard access to start, force-start, and quit via
  mnemonics
- the prompt content is focusable and read by screen readers before rating
- Space can reveal the response without a pre-response rating
- the response content becomes focusable after the pre-response rating or
  direct reveal
- numeric keys activate ratings directly
- `e` opens the current card for editing after reveal and returns focus to the
  previous post-response control
- the statistics dialogue focuses the summary text first
- the card editor uses normal text controls for prompt and response editing
- informative messages are intentionally concise and avoid repeating focus
  information that the screen reader already announces

Accessibility regressions should be treated as blocking defects.

The beta accessibility acceptance check is recorded in
[docs/accessibility-acceptance.md](docs/accessibility-acceptance.md).

Known defect: on the target Windows screen-reader stack, tabbing or
shift-tabbing into the ready-screen prompt list can announce the selected item
twice. Arrow-key navigation inside the list, selection, edit, remove, and
review startup remain functional. This is currently treated as a known native
list accessibility defect rather than a release blocker.

Known defect: when the ready list is empty, some screen reader and wxWidgets
combinations announce the empty list as "unknown". The ready summary and filter
counts remain the reliable way to confirm that the current view has no cards.

## Version Control

This repository uses Fossil, not Git.

Useful commands in this checkout:

```bash
FOSSIL_HOME="$PWD" fossil status
FOSSIL_HOME="$PWD" fossil diff
FOSSIL_HOME="$PWD" fossil add path/to/file
FOSSIL_HOME="$PWD" fossil commit --nosync path/to/file -m "Describe the change"
```

`--nosync` is currently relevant because this checkout may try to autosync
against a readonly peer checkout and fail before the local commit completes.

This checkout also carries a Fossil `before-commit` hook in
[.fossil-settings/hooks](.fossil-settings/hooks).
If you absolutely have to bypass that hook, Fossil supports `--no-verify`.

If you add a new file such as an XRC resource, remember to `fossil add` it
before committing.
