Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

History Recording Design

Overview

Every completed training session is appended as a single JSON line to a log file. This allows post-hoc analysis of typing speed, accuracy trends, and per-key performance without any in-app reporting UI.


File location

~/.local/share/rstype/history.jsonl

This follows the XDG Base Directory Specification:

  • ~/.config/rstype.toml — configuration (settings the user edits)
  • ~/.local/share/rstype/history.jsonl — application data (generated by the app)

History is data accumulated by the app, not something the user configures, so ~/.local/share is the correct location by that convention.

Why ~/.local/share/rstype/? This follows the XDG Base Directory Specification for user-specific application data on Linux. It keeps training data separate from configuration (~/.config/rstype.toml) and out of the home directory root.


File format: JSONL

One JSON object per line, appended on every session completion.

Why JSONL over SQLite? SQLite would enable richer in-process queries but adds a native dependency and significantly more complexity. JSONL is append-only, requires no schema migrations, is readable with any text tool (cat, grep, jq), and can be imported into any analysis tool (Python, R, DuckDB, etc.) trivially.

Why JSONL over plain CSV? The keystrokes field is a variable-length array. CSV cannot represent nested structures cleanly without quoting hacks or splitting into multiple files.


Record structure

{
  "timestamp": "2026-04-04T15:08:00Z",
  "text": "The quick brown fox jumps over the lazy dog",
  "mode": "forward",
  "wpm": 65.3,
  "errors": 2,
  "keystrokes": [
    {"typed": "T", "offset_ms": 0},
    {"typed": "h", "offset_ms": 312},
    {"typed": "Backspace", "offset_ms": 850},
    {"typed": "h", "offset_ms": 1103}
  ]
}

Fields

FieldTypeDescription
timestampstringISO 8601 UTC timestamp of when the session completed
textstringThe target text that was trained on
modestringTyping mode: "forward" or "stop"
wpmnumberWords per minute (chars / 5 / elapsed minutes)
errorsnumberTotal wrong keypresses during the session
keystrokesarrayOrdered list of every key pressed, from first to last

Keystroke fields

FieldTypeDescription
typedstringThe key that was pressed, in W3C format (see below)
offset_msnumberMilliseconds since the first keypress of the session

Why record every keypress (not just correct ones)? Wrong keypresses, backspaces, and hesitations are precisely where skill gaps live. Recording only correct keys would discard the most valuable training signal.

Why no expected field per keystroke? It is redundant. The target text is stored in the text field, and the position of each correct keystroke in the sequence can be derived from it. Storing expected would bloat the log for no additional information.


Key name standard: W3C KeyboardEvent key values

Key names follow the W3C UI Events KeyboardEvent key Values specification.

Examples:

KeyStored as
Letter a"a"
Letter A (shifted)"A"
Space" " (literal space character)
Backspace"Backspace"
Enter"Enter"
CapsLock"CapsLock"
Left arrow"ArrowLeft"
Escape"Escape"

Why W3C key values over USB HID keycodes (numbers)? USB HID codes are more compact (1–2 digits vs. 9 characters for "Backspace") but the size difference is negligible (~2 bytes per keystroke over a 43-character exercise). W3C key strings are self-documenting, require no lookup table to interpret, and are the closest thing to a universal cross-platform string standard for key names.