12 KiB
viexp Roadmap — Rust + English in 20-hour sprints
Method: Josh Kaufman, "The First 20 Hours" — rapid skill acquisition. The project is split into isolated 20-hour sprints (~45 min/day for a month each). Every sprint: one Rust sub-skill, one working app increment, one English artifact. The goal of each sprint is to cross the frustration barrier and ship something that runs — not perfect code.
Kaufman's rules, adapted
| Kaufman principle | How this roadmap applies it |
|---|---|
| Deconstruct the skill | The table below: each sprint = one sub-skill + one app increment |
| Learn just enough to self-correct | Per-sprint "Rust focus — the vital 20%": the minimum theory to read your own compiler errors. Every error goes to the ErrorJournal with a self-correction cue |
| Remove barriers to practice | Sprint 0 sets up the whole environment: toolchain, linters, fast feedback (bacon), Gitea board, CI. Never debug your setup during practice time |
| Fast feedback loops | cargo check/bacon on save, unit tests per session, immediate AI code review of each session's diff (commit → review → fix) |
| Quantity over quality | Many small commits, many small drills. Working ugly code beats beautiful unfinished code. No over-engineering before v0.1 |
Skill deconstruction
Rust sub-skills (learned in order): cargo & project layout → types & control flow →
ownership/borrowing → structs, enums, pattern matching → Option/Result & ? →
modules & crates → traits & generics → iterators → Path/fs & error handling (thiserror/anyhow) →
serde/TOML → lifetimes → trait objects & dynamic dispatch → threads & channels →
async/await & tokio → process spawning → caching & performance.
App increments (each demoable): vls CLI → 3-pane TUI → navigation & file ops →
config & openers → text previews → image previews → document previews → media & async →
script plugins → power features → performance → release.
English track: every commit message, every issue, all docs — English only. One written artifact per sprint. Daily DevLog (3–5 sentences). See workflows/english-workflow.
Session rhythm (45 min, every day)
- 5 min — read yesterday's DevLog + ErrorJournal;
git pull,baconstarts. - 30 min — today's drill or feature slice (one drill = one commit).
- 10 min — get the diff reviewed, fix what the reviewer flags, write the DevLog entry.
Frustration rules: stuck >20 min on one error → ask for a review instead of grinding; never end a session with broken code (revert to green); a slow day is a reading day (Rust Book chapter in English) — log it, no guilt.
Sprints
Legend: 🎯 milestone. Each sprint gets a docs/sprints/sprint-NN-*.md note (Sprint template)
and a Gitea milestone with issues created from its Definition of Done.
Sprint 0 — Setup & deconstruction (≈6 h, short)
- App deliverable: empty
viexpcargo project that compiles,cargo testruns one trivial test, CI (Gitea Actions) is green,bacon+clippy+rustfmtwired, Gitea board ready. - Rust focus: toolchain mental model — what cargo, rustc, crates.io,
Cargo.tomlare; read your first compiler error on purpose (break a program, fix it). - English: README "Status" section + the vault (this roadmap counts).
- DoD:
cargo baconshows check+test on save; first commit pushed; Sprint-1 issues exist.
Sprint 1 — Rust core via vls (20 h)
- App deliverable:
viexp lssubcommand — a betterls: colored names by type, human-readable sizes,--sort name|size|mtime,--hidden,--long; ≥10 unit tests. - Rust focus (vital 20%): variables & types, functions,
if/match, loops,Vec/Stringvs&str, structs & enums,Option/Result+?, modules,#[cfg(test)]. Rust Book ch. 1–9 (skim 7/8), rustlingsintro→enums. - English: README usage section; article "Why build a file manager in Rust" (draft).
- DoD:
vls ~/output beatslsfor your eyes; clippy clean; tests green.
Sprint 2 — First TUI (20 h) — the borrow-checker sprint
- App deliverable: three-pane Miller layout (parent / current / placeholder preview),
j/k/gg/Gcursor movement,:qquits, resize-safe redraw, no flicker. - Rust focus: ownership & borrowing in anger (the state struct owns everything), references vs clones, lifetimes as they appear in ratatui calls, the event-loop pattern (poll event → mutate state → redraw). Rust Book ch. 4, 10.3 (skim), ratatui official docs.
- English: keymap reference table in docs (precise imperative phrasing).
- DoD: navigate a 10k-file directory smoothly; panic-free for 15 min of use.
Sprint 3 — Navigation & file ops (20 h) 🎯 M1: personal daily driver
- App deliverable: enter/leave directories, hidden toggle, sort cycling,
Space/Vselection,yy/dd/ppcopy/cut/paste, delete → first-class trash (freedescompliant) with undo,:mkdir :touch :rename, status bar (path, size, free space — not per-framestatvfs; 1 Hz poll). - Rust focus:
Path/PathBuf,fs::read_dir/metadata, real error handling (thiserrorfor lib-style internals,anyhowat main), iterators (map/filter/sort_bychains),Displayimpls. - English: article "Week one of dogfooding my own file manager".
- DoD: use viexp instead of ranger for real work for 3 days; log every pain point as an issue.
Sprint 4 — Config & openers (20 h)
- App deliverable:
viexp.toml(defaults, theme colors, sort) +modules.tomlregistry v0 (ADR-003): mime/glob → opener, per-moduleenabled, user rules prepend/append; opener engine (infer + xdg-mime → rule table →xdg-openfallback),r"open with" menu,:open_with. - Rust focus: serde derive on enums/structs,
Default+ merge semantics,HashMap/BTreeMap, first trait design (Opener), builder-ish config loading with helpful errors. - English: configuration guide draft (reference-style writing).
- DoD: any file opens with your preferred app from config alone; broken TOML produces a friendly error, not a panic.
Sprint 5 — Text previews & bulk rename (20 h)
- App deliverable: preview pane v1 — syntax-highlighted text (syntect) with line numbers
and scrolling, directory preview, file metadata panel, zip/tar listing,
:bulkrenamevia$EDITOR(ranger's killer feature),n/Nplain search,:command history. - Rust focus: lifetimes in real signatures, trait objects (
Box<dyn Previewer>registry), advanced iterators, caching keyed by(path, mtime). - English: article "How a TUI paints text" (explaining rendering → strongest writing practice).
- DoD: preview parity with ranger for text/code/archive files.
Sprint 6 — Image previews (20 h) 🎯 M2a
- App deliverable: image module through the registry; kitty graphics adapter first
(owner's terminal), chafa/halfblocks floor; thumbnail disk cache + LRU; runtime
disable/replace via
modules.tomlproven on images. - Rust focus: the
imagecrate, decode/resize pipeline,#[cfg(feature)]modules, pixel data, spawning helper processes safely. - English: article "How terminals display images" (kitty protocol, sixel, ueberzug++ — your best future blog post; research notes already hold the material).
- DoD: PNG/JPEG/WebP/GIF preview instantly in kitty;
enabled=falsekills it in one line.
Sprint 7 — Document previews (20 h) 🎯 M2b: full ranger replacement
- App deliverable: PDF (pdfium-render, Apache-2.0), EPUB (hand-rolled zip+XML — GPL
trap avoided), Markdown (comrak/termimad), DJVU (djvu-rs +
ddjvufallback config). All as registry modules, all runtime-disableable. - Rust focus: binary data & byte streams, feature-gated crates, error taxonomy design, more trait objects; reading crate docs as a skill.
- English: module documentation pages (PDF/EPUB/DJVU) in user-guide style.
- DoD: your entire document library previews; ranger uninstalled.
Sprint 8 — Media & async (20 h) 🎯 M2c
- App deliverable: video thumbnail (spawn
ffmpeg -ss … -vframes 1), audio metadata + cover art (ffprobeJSON), background preview pipeline: std threads + mpsc now, generation-counter cancellation, large-directory pagination; adopt tokio for the pipeline by sprint end (ADR-005). - Rust focus:
std::thread,mpsc,Arc/Mutex, then async/await,tokio::spawn,select!, cancellation patterns. Rust Book ch. 16 + async book chapters (English only!). - English: article "Async Rust for a skeptic" — explain threads-vs-tokio in your own words.
- DoD: 4K-video directory scrolls at full speed; huge directory never blocks input.
Sprint 9 — Script plugin protocol (20 h) 🎯 M3a: extensible
- App deliverable: freeze the external plugin contract (ADR-002 phase 2): previewer
argv
(path, w, h, x, y)+ env context + FIFO write-back +cleanerhook; documented exit codes & SIGPIPE; opener scripts;plugins/dir discovery; two reference plugins (bash: torrent info; python: git repo summary). - Rust focus: process spawning & pipes, timeouts, safe command construction (no shell injection), protocol design & semver, integration tests with fixture scripts.
- English: plugin author guide — the sprint's main artifact; write it as if for strangers.
- DoD: a script written only from the guide (no source peeking) works.
Sprint 10 — Power features (20 h) 🎯 M3b: feature parity with your ranger config
- App deliverable: tabs, bookmarks + marks, fuzzy finder (nucleo) with interruptible
search (broot lesson),
:commandsset (:find :delete :copy…),pushkey-simulation, shell integration--choosefile/--choosedir/--selectfile, cd-on-exit wrapper script, session restore. - Rust focus: state machines (modes), Rc-free architecture review,
macro_rules!for keymap tables, API refactoring under tests. - English: article "Vim-style UX patterns in file managers".
- DoD: your shell rc sources the viexp wrapper; fuzzy find feels instant.
Sprint 11 — Performance & robustness (20 h)
- App deliverable:
notify-based live directory updates, virtual scrolling, startup <50 ms, one-week dogfood with zero panics,tracinglogs to file, panic hook restores the terminal, criterion benchmarks committed, crash-fix buffer. - Rust focus: profiling (
cargo flamegraph,perf), benchmarking (criterion), reading someone else's code (yazi's) for patterns, hardening. - English: article "Profiling a TUI app: making viexp start in 40 ms".
- DoD: benchmark numbers in README; a week of daily use logged.
Sprint 12 — Release & docs (20 h) 🎯 M4: v0.1.0 public
- App deliverable:
v0.1.0— cargo-dist release builds, AUR PKGBUILD, Gitea release + changelog, user guide (mdBook in-repo), plugin examples gallery, install docs. - Rust focus: release engineering, MSRV policy, feature matrix testing, rustdoc comments on the public plugin API.
- English: the user guide is the largest English artifact of the project; polish it hard.
- DoD: a stranger installs from AUR and writes a plugin using only the docs.
Backlog (post-1.0, priority order)
Embedded Lua plugins (mlua, ADR-002 phase 3) · sixel/iTerm2/ueberzug++ adapters · DDS-style
inter-instance pub/sub · NNN_FIFO-style hover event stream · themes gallery · zoxide jump ·
archive mount/browsing depth.
Milestones
| Milestone | After sprint | Meaning |
|---|---|---|
| M1 | 3 | daily driver for basic navigation/file ops |
| M2a–c | 6–8 | full ranger replacement (images, docs, media) |
| M3a–b | 9–10 | extensible by scripts, feature parity |
| M4 | 12 | v0.1.0 released publicly |
At 45 min/day this is roughly a 12–13 month journey to v0.1.0 — the point is a working product and durable skills, in that order, every single sprint.
Cadence & safety nets
- Sprint notes live in
docs/sprints/; each sprint's DoD becomes Gitea issues (milestone per sprint) — see workflows/gitea-workflow. - If a sprint overruns by >30%, cut scope from the bottom of its DoD — never silently skip tests.
- One "buffer week" is allowed between sprints; more than one means the sprint was too big — re-decompose in the retro.