DotState is a terminal-based dotfile manager built with Rust (ratatui + git2). TUI and CLI for managing dotfiles through Git repos with profiles, symlink tracking, backups, and package management.
For full development guidance, load the dotstate-dev skill.
cargo build # Build
cargo run # Run TUI
cargo run -- list # Run CLI command
cargo test # Run all tests
cargo fmt && cargo clippy # Format + lint (REQUIRED before committing)src/
├── app.rs # Main event loop, screen routing, ScreenAction dispatch
├── main.rs # Entry point, CLI parsing, terminal setup
├── cli.rs # CLI command definitions
├── ui.rs # Screen enum, shared state structs
├── styles.rs # Theme definitions and color system
├── git.rs # Low-level git operations (git2 + system git for SSH)
├── screens/ # Screen controllers (implement Screen trait)
├── components/ # Reusable UI (header, footer, help_overlay)
├── services/ # Business logic (git, sync, profile, package)
├── utils/ # Infrastructure (symlink_manager, backup_manager, etc.)
├── widgets/ # Custom ratatui widgets
└── keymap/ # Keyboard config with presets (Standard, Vim, Emacs)
Data flow: App::run() polls crossterm events -> screen's handle_event() -> returns ScreenAction -> App processes action -> screen's render() draws UI.
- Use
SymlinkManagerfor DotState-managed symlinks - Do not call raw symlink APIs for home↔repo managed links (tracking + backups live inSymlinkManager). Exception: preserving internal content symlinks during recursive copy (copy_dir_all) is allowed. - Never hardcode colors - Always use
theme()fromcrate::styles - Never hardcode keys - Always use the keymap system via
ctx.config.keymap.get_action() - Always use Services layer for business operations (never bypass with direct file/symlink ops)
- Guard text input focus - At the top of
handle_event, checkis_text_input_focused()before matching actions, or 'q' will quit instead of typing - After modifying common files in manifest, always call
ProfileService::ensure_common_symlinks() - Validate before syncing directories -
validate_before_sync()must run beforecopy_dir_all()(circular symlinks cause crashes) - Mouse support is required - All new screens, popups, and interactive components must support mouse click-to-focus/select and scroll. Store
Rectareas duringrender(), hit-test inhandle_event(). Block background interactions when popups are open.
cargo fmtcargo clippy- fix all warningscargo test(if applicable)- Update
CHANGELOG.mdunder[Unreleased]with format:- **Component**: Brief description
Never commit or push without explicit user permission. No exceptions. The user will handle commits. Just finish the work. if you are instructed to commit do not add Co-Author line
| Purpose | Path |
|---|---|
| Config | ~/.config/dotstate/config.toml |
| Storage | ~/.config/dotstate/storage/ (default) |
| Symlink tracking | ~/.config/dotstate/symlinks.json |
| Package Check cache | ~/.config/dotstate/package_status.json |
| Backups | ~/.dotstate-backups/ |
| Profile manifest | <repo>/.dotstate-profiles.toml |
| Design decisions | docs/MEMORY.md |