Skip to main content

Adaptive drills for your weakest keys

Project description

Keystrike

Adaptive drills for your weakest keys — an offline terminal typing tutor inspired by keybr.com. Stats stay on your machine; nothing phones home.

Keystrike demo

What it does

Keystrike tracks how fast and accurately you type each key, unlocks new letters as you hit your targets, and generates practice text that overweight your current weak spot. Switch keyboard layouts (QWERTY, Dvorak, Colemak, Colemak Mod-DH, or your own TOML) and each layout keeps its own history.

Features

  • Adaptive engine — row-weighted key unlock order, speed+accuracy confidence gates, Markov word drills with a guaranteed focus letter.
  • Per-layout stats — heatmap with per-key confidence and urgency; WPM/accuracy trends; press a key on the heatmap for that key's history.
  • Daily learn budget — optional cap on adaptive minutes per calendar day.
  • Custom layouts — drop *.toml files into your config layouts directory; no restart needed.
  • Git backup sync — optional CLI to push/pull settings and sessions to a private remote (union-merge sessions, last-write-wins settings).
  • Offline by default — JSONL session logs and a local stats cache under platformdirs paths; sync is opt-in.

Install

Requires Python 3.12+ and a terminal with raw-mode keyboard input (Terminal setup).

pipx install keystrike    # or: uv tool install keystrike
keystrike                 # launch TUI (default)
keystrike --version

Or from source:

git clone https://github.com/egno/keystrike
cd keystrike
uv sync --no-dev
uv run keystrike

Usage

Home

Key Action
Enter Start adaptive practice
s Stats
o Settings
l Cycle layout
Ctrl+Q Quit

On other screens, Esc / q goes back. Settings saves with Ctrl+S.

Practice

Adaptive mode disables backspace — mistakes stay in the record so confidence scores stay honest. The HUD shows live accuracy, remaining daily learn time, and the current focus key. When a session ends, the next lesson starts automatically unless you go back or hit your daily limit.

Stats

Recent sessions are listed below the heatmap. Press any key on the heatmap to drill into that key's confidence trend; Esc / q returns to the overview.

Settings

Setting Default Notes
Layout qwerty Any bundled or custom layout
Target speed 46 WPM Or CPM — your unlock threshold
Letters unlocked up front 16 Force-unlocked before confidence gating
Daily learn limit 10 min 0 = unlimited

Backup sync

Opt-in git sync for backing up or moving data between machines. Requires git on PATH and a private remote (sessions contain your typing history).

keystrike sync init git@github.com:you/keystrike-backup.git   # one-time
keystrike sync push      # local → remote
keystrike sync pull      # remote → local (rebuilds stats cache)
keystrike sync status    # diff summary

Sync merges sessions by session_id (union), resolves settings by updated_at (last-write-wins), and copies layout files both ways. The stats cache is excluded — pull triggers a rebuild.

Data locations

Path Contents
~/.config/keystrike/settings.toml User settings
~/.config/keystrike/layouts/ Custom layout TOML files
~/.config/keystrike/sync.toml Sync remote config (after sync init)
~/.local/share/keystrike/sessions/ Session JSONL logs (Linux)
~/Library/Application Support/keystrike/ Same on macOS

Windows uses %APPDATA% / %LOCALAPPDATA% equivalents via platformdirs.

Terminal setup

Keystrike captures every keystroke in raw mode via Textual.

Works out of the box in Terminal.app, iTerm2, and most Linux terminals.

Windows

Use Windows Terminal — the legacy conhost host has unreliable raw-mode support. Run keystrike inside WT, not cmd.exe. Raw mode is not verified on every Windows build; please open an issue if something breaks.

Development

uv sync                  # runtime + dev (pytest, pyright)
uv run pytest -q
uv run pyright
uv sync --all-groups      # + ruff + snapshot tests (desktop only)
uv run ruff check

Dependency groups: dev (default, pure Python — safe on Termux), lint (Ruff), snapshot (pytest-textual-snapshot). Keep native-wheel tools out of dev; see pyproject.toml for why.

Regenerate the demo GIF after UI snapshot changes:

uv sync --group snapshot
uv run pytest tests/presentation/test_snapshots.py --snapshot-update
uv pip install pillow cairosvg   # one-off; system cairo on macOS/Linux
uv run python scripts/generate_demo_gif.py

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

keystrike-1.1.0.tar.gz (63.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

keystrike-1.1.0-py3-none-any.whl (83.3 kB view details)

Uploaded Python 3

File details

Details for the file keystrike-1.1.0.tar.gz.

File metadata

  • Download URL: keystrike-1.1.0.tar.gz
  • Upload date:
  • Size: 63.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.33 {"installer":{"name":"uv","version":"0.11.33","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for keystrike-1.1.0.tar.gz
Algorithm Hash digest
SHA256 0e922a7a7575f62cca05bf66d02b39ca0eaa8f0175cd08545458092337bcfcb4
MD5 c5c9875573cb7b4484a203c743365b3f
BLAKE2b-256 0421d0193ae56ab40e2ac42a14998b99759b120486e9beca08e5483171787b73

See more details on using hashes here.

File details

Details for the file keystrike-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: keystrike-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 83.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.33 {"installer":{"name":"uv","version":"0.11.33","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for keystrike-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1df13452b9d8827a53759f07bc1cd07e7911cb1c5742f037d9687d5f687db42c
MD5 5d42ba33257a1fd3a581af9bf4afbd31
BLAKE2b-256 6bdd0a074f413429a6285b7a60d1229d176d74ef6f321f6fdefedc22835dae25

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page