Purpose: Documents chosen frameworks, libraries, development tools, and technical constraints Type: Steering Document - Technology decisions and rationale Related: See
product.mdfor product vision,structure.mdfor how we organize code
Why Rust:
- Performance: Near-zero overhead for real-time input processing (<50ms latency requirement)
- Terminal Control: Excellent ecosystem for TUI applications
- Type Safety: Prevents entire classes of bugs at compile time
- Memory Safety: No garbage collection pauses that could affect typing feedback
- Cross-platform: Works on Linux, macOS, Windows with same codebase
- Developer Experience: Cargo provides excellent build, test, and dependency management
Alternatives Considered:
- Go: Good performance, but less mature TUI ecosystem
- Python: Rapid development, but performance concerns for real-time feedback
- C/C++: Maximum performance, but unsafe and complex for this use case
Purpose: Terminal UI framework
Why ratatui:
- Modern, actively maintained (fork of archived tui-rs)
- Declarative UI approach (similar to React)
- Excellent widget system for layouts
- Strong community and documentation
- Supports all major terminal backends
What it provides:
- Layout system (blocks, borders, panels)
- Text styling and coloring
- Frame rendering optimization
- Widget composition
Alternatives Considered:
- cursive: Higher-level but less flexible for custom layouts
- termion: Lower-level, more manual work required
- tui-rs: Archived, ratatui is the successor
Purpose: Cross-platform terminal manipulation
Why crossterm:
- Cross-platform (Windows, macOS, Linux)
- Event handling (keyboard, mouse, terminal resize)
- Raw mode control
- Direct cursor manipulation
- ANSI color support
What it provides:
- Keyboard event capture (character-by-character input)
- Terminal mode switching (raw vs cooked)
- Screen clearing and cursor positioning
- Event polling for responsive UI
Alternatives Considered:
- termion: Unix-only, not cross-platform
- pancurses: C bindings, less Rust-idiomatic
Purpose: Serialization and deserialization
Why serde:
- Zero-cost serialization framework
- Type-safe JSON handling
- Derive macros reduce boilerplate
- Industry standard in Rust ecosystem
What it provides:
- Struct β JSON conversion
- Automatic field serialization
- Human-readable stats files
Usage:
#[derive(Serialize, Deserialize)]
struct Stats {
sessions: Vec<SessionRecord>,
}Purpose: Date and time handling
Why chrono:
- Comprehensive time/date library
- Timezone support
- Duration calculations
- RFC 3339 timestamp formatting
What it provides:
- Session timestamps
- Duration tracking
- Human-readable time formatting
Alternatives Considered:
- time: Simpler, but less feature-complete
- std::time: Insufficient for timestamp formatting needs
Purpose: Command-line argument parsing
Why clap:
- Derive-based API (ergonomic)
- Automatic help generation
- Subcommand support
- Shell completion generation
Current Usage:
- Prepared for future phases (Phase 1 has no CLI args)
Future Usage:
typer-cli --lesson homerow-3
typer-cli --stats
typer-cli --mode codeAlternatives Considered:
- structopt: Merged into clap 3.0
- argh: Simpler but less feature-complete
Purpose: Build system and package manager
Usage:
cargo build # Development build
cargo build --release # Optimized build
cargo test # Run test suite
cargo clippy # Linting
cargo fmt # Code formattingPurpose: Rust linter
What it catches:
- Common mistakes and anti-patterns
- Performance issues
- Idiomatic Rust violations
- Potential bugs
Purpose: Code formatter
Configuration: Default settings (Rust style guide)
Framework: Built-in #[cfg(test)] and #[test]
Coverage:
engine/scoring.rs: WPM and accuracy calculationsengine/types.rs: TypingSession logiccontent/generator.rs: Lesson generationdata/storage.rs: JSON persistencekeyboard/azerty.rs: Layout definitions
Current Status: 29 passing tests
Approach: End-to-end session tests
What's tested:
- Complete typing session flow
- Stats persistence across restarts
- Input validation and feedback
- Deterministic test cases
- Edge cases (empty sessions, 100% accuracy, 0% accuracy)
- Performance benchmarks for input processing
[profile.dev]
opt-level = 0
debug = trueUse for: Development, testing, debugging
[profile.release]
opt-level = 3
lto = true
codegen-units = 1Use for: Production builds, benchmarking
src/
βββ main.rs # Minimal entry point
βββ app.rs # Application state and event loop
βββ ui/ # UI rendering (separation of concerns)
βββ engine/ # Core business logic (testable)
βββ content/ # Lesson generation (extensible)
βββ data/ # Persistence (swappable backend)
βββ keyboard/ # Layout definitions (multi-layout support)
Benefits:
- Testability: Business logic isolated from UI
- Extensibility: Easy to add new lesson types or layouts
- Maintainability: Clear boundaries and responsibilities
- Reusability: Engine can be used in other contexts
Approach:
- Direct terminal input (no buffering)
- Minimal processing per keystroke
- Pre-generated lesson content
- Efficient ratatui rendering
Target: <10MB resident memory
Approach:
- No large data structures
- Streaming stats to disk
- Minimal history retention in memory
Target: <5MB release binary
Current: ~2.8MB (stripped release build)
- Linux: Primary development platform (Manjaro, Ubuntu)
- macOS: Secondary testing
- Windows: Supported via crossterm, but lower priority
- Minimum: ANSI color support, cursor control
- Tested: kitty, alacritty, gnome-terminal, iTerm2, Windows Terminal
- Not supported: Very old terminals without ANSI escape codes
Location: ~/.config/typer-cli/ (XDG Base Directory standard)
Why XDG:
- Standard on Linux
- Clean separation from home directory
- Easy to backup/reset
Format: JSON (human-readable)
File: ~/.config/typer-cli/stats.json
Why JSON:
- Human-readable for debugging
- Easy to parse with external tools
- Serde provides automatic serialization
- Future-proof for schema evolution
Alternatives Considered:
- SQLite: Overkill for simple append-only data
- Binary format: Not human-readable, harder to debug
- TOML/YAML: No significant advantage over JSON
- Graphing: Consider
plottersfor terminal-based graphs - Colors: May add
coloredcrate for more sophisticated color schemes - Fuzzy matching: If adding lesson search/selection
- Plugin system: Consider
libloadingfor dynamic lesson loading - Themes: JSON-based theme definitions
- Custom layouts: JSON keyboard layout definitions
- Terminal input is inherently safe (limited to printable chars)
- No external input beyond keyboard
- Stats file written to user's own config directory
- All dependencies from crates.io (trusted source)
- Regular
cargo auditfor known vulnerabilities - Minimal dependency tree to reduce attack surface
cargo check # Fast compilation check
cargo test # Run test suite
cargo clippy # Lint
cargo run # Run in debug modecargo build --release # Optimized build
strip target/release/typer-cli # Remove debug symbols
cargo test --release # Test optimized build- Source: GitHub repository
- Binary releases: GitHub Releases
- Package managers: AUR (Arch), cargo install, Homebrew (macOS)
- VS Code + rust-analyzer
- Neovim/Vim + rust-analyzer (LSP)
- IntelliJ IDEA + Rust plugin
- Rust: 1.70+ (via rustup)
- Cargo: Included with Rust
- Git: Version control
- cargo-watch: Auto-rebuild on file changes
- cargo-audit: Security vulnerability scanning
- hyperfine: Benchmarking startup time