keybr-tui 0.2.1

Adaptive terminal (TUI) typing trainer in Rust that ports the keybr.com algorithm, runs offline, and imports your keybr.com data
# CLAUDE.md — keybr-tui Agent Context

Project constraints and environment for AI agents working on this codebase.

## Project Constraints

- **MVP only**: Do not implement menus, profile persistence, config files, or multiplayer. Defer everything to post-MVP.
- **Algorithm fidelity**: The text generator must mirror Keybr's algorithm exactly — no wordlists, no random characters.
- **State in `App` only**: No mutable globals. All runtime state lives in `src/app.rs`.
- **Strict MVU separation**: `ui.rs` reads state, never writes it. `update.rs` writes state, never renders.
- **Terminal-native colors only**: No hex/RGB. Use ANSI colors (the palette is defined in the engine module).

## Architecture

The project follows a Model-View-Update (MVU) pattern:

- `src/app.rs` — Application state (the Model). All mutable state lives here.
- `src/update.rs` — Event handling and state mutations (the Update). Never renders.
- `src/ui.rs` — Rendering (the View). Reads state, never writes it.
- `src/engine/` — Adaptive text generation (Markov chains, letter scheduling).
- `src/metrics.rs` — Per-key statistics and confidence tracking.
- `src/persistence.rs` — Saving/loading stats and config.
- `src/events.rs` — Terminal event channel (keyboard input, tick events).

## Environment

- OS: Arch Linux, shell: fish (use `;` not `&&`; use `set -x` not `export`)
- Build: `cargo build`, run: `cargo run`
- Test: `cargo test`
- Format: `cargo fmt --all`
- Lint: `cargo clippy --all-targets -- -D warnings`
- Editor: nvim

## Before pushing

Run all CI checks locally first — pushing with failing CI generates noise:

```fish
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test
cargo build
```

**Always commit `Cargo.lock` alongside `Cargo.toml` changes.** This is a binary
crate — the lock file ensures reproducible builds and is required for
`cargo publish` and `cargo install --locked`.

## Releasing a New Version

Mirrors the whisrs release process (see `~/Projects/whisrs/CLAUDE.md`), with
keybr-tui specifics noted.

**Versioning**: incremental feature/fix releases bump PATCH on the current
minor line (like whisrs's v0.1.x train — currently v0.2.x here). Reserve a
MINOR bump for milestone-level changes (new practice modes, multi-language).
crates.io versions are immutable — never retag or republish a shipped version.

1. **Bump version** in `Cargo.toml`, `flake.nix`, and `contrib/PKGBUILD`
   (`pkgver`); run `cargo build` so `Cargo.lock` picks up the new version,
   and commit the lock file with the bump.
2. **Update `CHANGELOG.md`** — new `## [X.Y.Z] - YYYY-MM-DD` section
   (Keep a Changelog format: Added / Changed / Fixed).
3. **Run all CI checks** locally (see above).
4. **Commit** as `chore(release): vX.Y.Z` and **push** to main.
5. **Tag and push**: `git tag -a vX.Y.Z -m "vX.Y.Z — summary"; git push origin vX.Y.Z`.
   The Release workflow builds binaries for 4 targets (Linux x86_64,
   macOS x86_64/aarch64, Windows x86_64) and creates the GitHub release.
6. **Write the release notes by hand** from the CHANGELOG section
   (`gh release edit vX.Y.Z --notes ...`) — auto-generated notes are
   disabled, same as whisrs, because they miss stacked PRs and read poorly.
7. **Publish to crates.io**: always run `cargo publish` after the tag —
   do not skip this step.
8. **Installer**: nothing to do — `install.sh` always serves the latest
   release and is auto-synced to gh-pages by `sync-installer.yml`.
9. **AUR**: not yet published. `contrib/PKGBUILD` is the in-repo template;
   when an AUR package exists it will be maintained in an external checkout
   (like `~/Projects/whisrs-git`), bumping `pkgver`, regenerating `.SRCINFO`
   with `makepkg --printsrcinfo > .SRCINFO`, and pushing to AUR.