diff --git a/README.md b/README.md index 72ef125..3485163 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,15 @@ A distraction-free, hackable, DIY writing machine. ESP32-S3 + e-ink + a real mechanical keyboard. You write Markdown, you commit, you push. Nothing else runs on it. -> **Status: pre-MVP, hardware on bench.** Display, USB keyboard, live typing -> with partial refresh, Wi-Fi + TLS, SD storage, and on-device git push are all -> verified in spikes; SD mount and save are now wired into the app binary. No -> release has shipped yet — v0.1's remaining gate is the boot splash and wiring -> git publish (`Ctrl-G` → push) into the app binary. Live per-item status: -> [`docs/macroplan.md`](docs/macroplan.md) · failure write-ups: -> [`docs/postmortems/`](docs/postmortems/README.md). +> **Status: v0.7 shipped, hardware on bench.** v0.1 (MVP — boots, edits, +> publishes) shipped 2026-07-11; v0.2 through v0.7 (vim navigation and editing, +> file palette + multi-buffer, Markdown affordances, `/` search, `:gp` push / +> `:gl` pull) followed within the week. Firmware is at 0.7.0; next up is v0.8 +> (battery + sleep). Live per-item status: +> [`docs/macroplan.md`](docs/macroplan.md) · doc index: +> [`docs/README.md`](docs/README.md) · failure write-ups: +> [`docs/postmortems/`](docs/postmortems/README.md) · improvement loops: +> [`docs/kaizen/`](docs/kaizen/README.md). --- @@ -25,12 +27,12 @@ Two file scopes coexist on the SD card — formal definitions in [`CONTEXT.md`](CONTEXT.md): - **Tracked** — lives in the git working copy, gets **Published** when the - user presses `Ctrl-G`. + user runs `:gp`. - **Local** — never leaves the device. Permanently-private: journal entries, scratch, things that aren't anyone else's business. There is no "promote to Tracked" gesture — scope is fixed at file creation. -Same editor, same keymap; the difference is just whether `Ctrl-G` (publish to +Same editor, same keymap; the difference is just whether `:gp` (publish to the remote) is offered. --- @@ -64,17 +66,17 @@ a discrete pick — energy, latency, or memory bending against an interval or si memory-safety review of the Rust `unsafe`/FFI surface (mostly `usb_kbd.rs`) is in [`MEMORY_AUDIT.md`](MEMORY_AUDIT.md). -| Layer | Choice | Notes | -| ------------- | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| HAL / runtime | `esp-idf-svc`, `esp-idf-hal` | std build: heap, threads, VFS, mbedtls, Wi-Fi stack. | -| Display | Custom SSD1683 driver (`src/epd.rs`) + `embedded-graphics` | Dual-controller 792×272 panel; dirty-rect partial refresh (~630 ms measured). | -| UI layer | Custom thin widget layer | Ratatui's API _shape_ without its char-grid terminal model ([ADR-002](docs/adr.md#adr-002-ui-strategy--custom-widgets-on-embedded-graphics-not-ratatui)). | -| Editor core | Custom, in-tree (`src/editor.rs`) | Modal (Normal / Insert / Visual / VisualLine / View / Command), motions, operators + text objects. Plain-ASCII buffer until the v0.2 UTF-8 work. | -| USB host | `esp-idf` TinyUSB bindings | Boot-protocol HID; verified on hardware (Spike 4). | -| Git | **libgit2 via `git2`**, built as an esp-idf component with mbedTLS (`firmware/components/libgit2/`) | `gix` was the original pick but can't push over HTTPS — the [ADR-004](docs/adr.md#adr-004-git-implementation--gitoxide-gix) kill-switch fired ([postmortem](docs/postmortems/2026-07-05-spike7-gix-https-push.md)). On-device add → commit → push verified; ~16 s cold-`:gp` [latency breakdown](docs/notes/sync-latency.md). | -| TLS | `mbedtls` via `esp-idf` | GitHub HTTPS with the chain checked against embedded roots; ≈35 KB heap measured during handshake (Spike 6). | -| Auth | HTTPS + GitHub PAT | v0.1 bakes credentials in at build time via `TW_*` env vars; provisioning + at-rest protection is [ADR-011](docs/adr.md#adr-011-credential-provisioning--how-the-pat-reaches-the-device-and-is-protected-at-rest) (open), on-device settings land in v0.9. | -| Filesystem | FAT on SD (`esp_vfs_fat`) | Working copy lives here. Internal LittleFS holds config. | +| Layer | Choice | Notes | +| ------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| HAL / runtime | `esp-idf-svc`, `esp-idf-hal` | std build: heap, threads, VFS, mbedtls, Wi-Fi stack. | +| Display | Custom SSD1683 driver (`firmware/src/epd.rs`) + `embedded-graphics` | Dual-controller 792×272 panel; dirty-rect partial refresh (~630 ms measured). Panel geometry + the in-memory `Frame` live in the shared `display/` crate. | +| UI layer | Custom thin widget layer | Ratatui's API _shape_ without its char-grid terminal model ([ADR-002](docs/adr.md#adr-002-ui-strategy--custom-widgets-on-embedded-graphics-not-ratatui)). | +| Editor core | Custom, in-tree (`editor/` crate) | Modal (Normal / Insert / Visual / VisualLine / View / Command / Palette), motions, operators + text objects; UTF-8 buffer fed by the dead-key composer; smartcase + accent-folded `/` search. Host-built and host-tested off the xtensa target. | +| USB host | `esp-idf` TinyUSB bindings | Boot-protocol HID; verified on hardware (Spike 4). | +| Git | **libgit2 via `git2`**, built as an esp-idf component with mbedTLS (`firmware/components/libgit2/`) | `gix` was the original pick but can't push over HTTPS — the [ADR-004](docs/adr.md#adr-004-git-implementation--gitoxide-gix) kill-switch fired ([postmortem](docs/postmortems/2026-07-05-spike7-gix-https-push.md)). `:gp` publish + `:gl` pull verified on device; ~16 s cold-`:gp` [latency breakdown](docs/notes/sync-latency.md); how the real notes repo went from a 611 s brick to a 24 s sync: [kaizen](docs/kaizen/real-repo-sync.md). | +| TLS | `mbedtls` via `esp-idf` | GitHub HTTPS with the chain checked against embedded roots; ≈35 KB heap measured during handshake (Spike 6). | +| Auth | HTTPS + GitHub PAT | v0.1 bakes credentials in at build time via `TW_*` env vars; provisioning + at-rest protection is [ADR-011](docs/adr.md#adr-011-credential-provisioning--how-the-pat-reaches-the-device-and-is-protected-at-rest) (open), on-device settings land in v0.9. | +| Filesystem | FAT on SD (`esp_vfs_fat`) | Working copy lives here (`/sd/repo` + `/sd/local`); editor prefs are a git-tracked [`.typoena.toml`](docs/typoena-toml.md) in the repo. | --- @@ -100,16 +102,16 @@ Releases are frequent, and every version is a usable artifact rather than a checkpoint. Per-version scope, current `[x]`/`[~]` marks, and the Macroplan source live in [`docs/macroplan.md`](docs/macroplan.md). -| Version | Theme | One-liner | -| ------------------------------------------------------- | ------------ | -------------------------------------------- | -| [v0.1](docs/macroplan.md#v01--mvp-it-writes-it-pushes--) | MVP | Boots, edits one file, `Ctrl-G` pushes. | +| Version | Theme | One-liner | +| --------------------------------------------------------- | ------------ | -------------------------------------------- | +| [v0.1](docs/macroplan.md#v01--mvp-it-writes-it-pushes--) | MVP | Boots, edits one file, `:gp` publishes. | | [v0.2](docs/macroplan.md#v02--vim-navigation--) | Vim nav | Normal/Insert, motions, line numbers. | | [v0.2.5](docs/macroplan.md#v025--international-input--) | Intl input | US-Intl dead keys: à é ê ç, `'`+space = `'`. | | [v0.3](docs/macroplan.md#v03--vim-editing--) | Vim edit | `dd yy p`, undo/redo, counts. | | [v0.4](docs/macroplan.md#v04--visual-mode--ex-commands--) | Visual + ex | `v`/`V` select + `y d c`, `gr` read, `:` ex. | -| [v0.5](docs/macroplan.md#v05--file-palette--multi-file--) | Files | `Ctrl-P` over `/repo` + `/local`, buffers. | +| [v0.5](docs/macroplan.md#v05--file-palette--multi-file--) | Files | `Cmd-P` over `/repo` + `/local`, buffers. | | [v0.6](docs/macroplan.md#v06--markdown-affordances--) | Markdown | Headings, list continuation, soft-wrap. | -| [v0.7](docs/macroplan.md#v07--search--better-git--) | Search + git | `/` search, `:Gpull`. | +| [v0.7](docs/macroplan.md#v07--search--better-git--) | Search + git | `/` search, `:gl` pull. | | [v0.8](docs/macroplan.md#v08--power-battery--sleep--) | Power | 18650 + sleep + lid switch. | | [v0.9](docs/macroplan.md#v09--robustness--) | Robustness | Crash-safe writes, reconnect, settings. | | [v1.0](docs/macroplan.md#v10--polish--) | Polish | Boot ≤ 3 s, fonts, themes, enclosure, guide. | @@ -120,21 +122,33 @@ source live in [`docs/macroplan.md`](docs/macroplan.md). ## Repo layout ``` -/firmware Rust crate, esp-idf-rs target +/firmware Rust crate, esp-idf-rs target — the app + on-device bins (SD card mounted at runtime contains /repo and /local) /src - main.rs app binary — editor + display + USB (SD/git not wired yet) - editor.rs modal editor core: buffer, modes, keymap, :commands + main.rs app binary — editor + display + USB + SD + git, wired epd.rs SSD1683 dual-controller e-ink driver usb_kbd.rs TinyUSB host glue, HID → key events - /bin on-device spike binaries (sd_fat, wifi_tls, git_push, - git_sync, git_smoke) + git_sync.rs :gp/:gl service — dirty-path journal, O(depth) splice + commit, push/pull on a dedicated 96 KB git thread + persistence.rs SD mount, atomic save, crash recovery + net.rs Wi-Fi + SNTP bring-up (bounded retry) + /bin on-device spike + bench binaries (sd_fat, sd_bench, + wifi_tls, git_push, git_sync, git_smoke, git_bench, + splash) /components/libgit2 libgit2 as an esp-idf CMake component (mbedTLS); source vendored as a git submodule - build.rs bakes TW_* env vars (Wi-Fi, PAT, author) — v0.1 config path + build.rs bakes TW_* env vars (Wi-Fi, PAT, author) — the config + path until v0.9's on-device settings +/editor modal editor core crate — buffer, modes, motions, + palette, search, render; host-built and host-tested + off the xtensa target +/display panel geometry + in-memory Frame (embedded-graphics + DrawTarget), shared by the epd driver and the editor +/keymap pure HID boot-keyboard decode — host-testable, fuzzable /spikes desktop spikes (spike7 git push proof, pre-device) -/docs ADRs, QFD, hardware, roadmap, per-version specs, - spikes.md, postmortems/, notes/ +/docs the design record — index: docs/README.md + (ADRs, QFD, macroplan, per-version specs, spikes.md, + postmortems/, notes/, tradeoff-curves/, kaizen/) /hardware enclosure — parametric OpenSCAD case (case/) + renders CONTEXT.md project glossary — Tracked / Local / Save / Publish, and the principles that fall out of them