# Chatter — Implementation Plan & Method **Status:** Living document — revised as we learn. Read the Changelog at the bottom for what changed. **Version:** 0.7 (2026-06-26) **Audience:** The Chatter development team (Andreas, Matt, and Claude as development assistant). > This document is the shared source of truth for *how* we build Chatter. It is > deliberately incremental: early phases will answer questions that later phases > depend on, and this document will be updated as those answers come in. If > something here is marked **(unknown / to confirm on-device)**, treat it as an > open question, not a decision. --- ## 1. What Chatter is Chatter is a minimal, purpose-built interface for a reMarkable tablet used as an **assistive-speech device** by a user who has difficulty speaking — she writes, and her conversation partner reads. Chatter **augments** the tablet; it does not replace the standard reMarkable GUI. The design priority is **intuitiveness under intermittent recall**: the user should not have to remember technical steps. See the full motivation and the user-experience reasoning in [`Chatter_application_proposal.md`](Chatter_application_proposal.md). Chatter's core actions, by expected frequency: 1. **Erase part of the text** — a simple, intuitive gesture (e.g. wiping a fingertip back and forth over an area). 2. **Erase the whole page** — a single gesture (e.g. a diagonal finger stroke, upper-right → lower-left). 3. **Toggle to/from the standard GUI** — *necessary*; Chatter must be able to hand off to the stock interface and be returned to. 4. **Save the current page** — *importance to the user is not yet confirmed*; a single button writes a timestamped transcript into a "Chatter" folder. --- ## 2. Target device and key constraints **Device: reMarkable Paper Pro Move — model RM03A.** (Identified from the official user-guide PDF linked in the proposal.) | Property | Value | Why it matters | |---|---|---| | Display | E Ink Gallery 3, **color**, 7.3", 954×1696 (264 PPI), backlit | Color refresh pipeline differs from older grayscale models | | Touch | Multi-point capacitive | Finger gestures (erase) are viable | | Pen | Active Marker / Marker Plus (flip-to-erase on Plus) | Pen and touch are **separate input streams** → we can tell finger from stylus natively | | SoC / RAM | ARM 1.7 GHz dual A55, 2 GB RAM, 64 GB | Standard ARM-Linux cross-compile target | | OS | "Codex" (custom Linux) | Stock note app is Xochitl (Qt/C++, proprietary) | | Dev access | Enable **developer mode**, which requires a **factory reset** | **Back up the device first** | **Key risk — this is the newest model.** The mature community frameworks (rmkit, libreMarkable, Plato, KOReader ports) were built against the older RM1/RM2 grayscale framebuffer and refresh ioctls. They likely **do not support the Paper Pro Move yet**, or only partially. We should expect to do **first-principles work** — discovering this model's framebuffer format, color refresh path, and input device nodes by probing the hardware over SSH — rather than relying on an existing framework. This raises the value of hands-on device access early and argues for a small, well-proven first milestone. --- ## 3. Roles - **Andreas** — development, with Claude's assistance, on his own Paper Pro Move over SSH. - **Matt** — installation and QA, including on-site testing with the end user on her tablet. Matt has the same model (Paper Pro Move). Matt may also take on development; the split will be worked out as the project progresses. - **Claude** — development assistant: writes/reviews code, drives the build-deploy loop over SSH where possible, and maintains this document. This document is how Matt stays in sync. When the design changes, the change lands here first. --- ## 4. Development phases The phases are ordered so each de-risks the next. **Toggle (necessary) precedes Save (provisional).** ### Phase 0 — Safety & access - **Back up first** (critical on the user's device; skippable on a new tablet with nothing saved). Enabling developer mode **performs a factory reset** — on the Paper Pro family, SSH is unavailable until developer mode is on, and turning it on wipes the device. Sync to the reMarkable cloud account before enabling. Document this backup procedure so Matt can repeat it. - **Enable developer mode:** Hamburger menu (upper left) → Settings → Software → Advanced → Developer mode → Accept. This factory-resets the device (deletes all local files; user data cleared on reboot). Re-pair with the reMarkable account afterward to access cloud content. (Disabling later requires reMarkable's recovery application.) - **Reconnect wifi** after the reset (the wifi config is wiped). - **Get SSH credentials:** Menu → Settings → Help → Copyright and licenses; the root username (`root`), password, and device IP addresses are under the "GPLv3 Compliance" header. USB exposes the tablet at `10.11.99.1`. - **Enable SSH over wifi (it is OFF by default):** connect over USB, SSH in, and run `rm-ssh-over-wlan on`. Only then is the listed `192.168.x.x` address reachable; after that the USB cable is optional. - Install your workstation's SSH public key into the tablet's `~/.ssh/authorized_keys` (user `root`) for passwordless access. - Confirm SSH login, `scp` of a binary, and remote execution. - Stand up the x86_64-hosted cross-toolchain for Codex OS; verify a trivial ARM binary runs on-device. > Dev environment note: development host is **Jatke** (on the wired LAN); we > connect to the tablet **over wifi** (USB not in use). ### Phase 1 — On-device investigation (no app code; produces a findings writeup) Answer the questions that can only be answered with the tablet over SSH. See the checklist in §5. Output: a short findings document added to `doc/`. **Status: substantially complete (2026-06-25)** — see [`Chatter_phase1_findings.md`](Chatter_phase1_findings.md). Key results: pen (`event2`) and finger (`event3`) are separate evdev devices; the display is DRM/KMS only (no fbdev) driven by `imx-drm`; and the stock app is a Qt 6.8.2 app rendering through a reusable **`epaper` QPA plugin** — so Chatter should be a Qt 6 app run with `-platform epaper`. Remaining sub-items (verifying `-platform epaper` from a third-party binary, input delivery, toggle hand-off) roll into the Phase 2 spike. ### Phase 2 — Minimal canvas spike Read the pen, render strokes to the (color) display, and clear the page — nothing more. This proves the two hardest pieces (input + color refresh) end to end and de-risks everything after it. **Status (2026-06-25): display/toolchain half PROVEN on hardware.** A third-party Qt Quick app (`build/chatter`) cross-built with the Chiappa SDK renders crisp black-on-white on the e-paper via `-platform epaper` (`QT_QUICK_BACKEND=epaper`). **Status (2026-06-26): inking WORKS, with one known quality issue.** Custom evdev pen reader (`src/PenDevice.cpp`, reads `event2`) drives a `QQuickPaintedItem` canvas (`src/InkCanvas.cpp`): ink tracks the pen, orientation correct, eraser (BTN_TOOL_RUBBER) erases, finger-tap "Clear" works, latency good. - **Known issue:** strokes render as a "dashed line that fills in" (two-pass), unlike the solid stock pen. **Root cause:** we use the panel's default *grayscale* mode. **Fix path:** xochitl wraps its writing area in a QML `ScreenModeItem` set to **Mono/FAST** with a dedicated **pen waveform** (`/usr/share/remarkable/ct33_pen.bin`). The control is the private `EPScreenModeItem` class in `libqsgepaper.so` (`setMode()`, modes Mono/FAST/FastGrayscale) — not a public QML type, no SDK header — so Chatter must integrate it directly (instantiate, link the plugin, drive `mode` via the meta-object, wrap the canvas). Antialiasing on/off does not affect it. - **Pen-style decision:** Chatter uses the pen style set in the standard GUI (xochitl.conf `LastPen`/`LastPenSize`/`LastPenColor`, readable via QSettings), re-read so it tracks changes the user makes after toggling — no style menu in Chatter. **Lessons learned (encoded in `scripts/`):** - The e-paper framebuffer is a **singleton guarded by an flock** (`/tmp/epframebuffer.lock`, from `libqsgepaper`'s `EPFramebufferAcep2`). Only ONE process may hold it; a stranded instance shows `Failed to lock epframebuffer` / `Failed to initialize SWTCON` and the panel stays blank. Always stop the previous instance first. Journal success marker: `SWTCON initialized \o/`. - **Run as a transient systemd service** (`systemd-run --unit=chatter …`), not an ssh background job (which holds the SSH channel open and can strand the process). Manage with `systemctl stop chatter` / `journalctl -u chatter`. - A full-screen `Window` needs an **explicit size** (`width: Screen.width; height: Screen.height`); `visibility: FullScreen` alone left it unsized/blank. - xochitl runs with **no special Qt env** — `-platform epaper` + `QT_QUICK_BACKEND=epaper` suffices. **Run recipe:** `scripts/build.sh && scripts/deploy-and-run.sh`; `scripts/restore-xochitl.sh` to return to the standard GUI. ### Phase 3 — Erase gestures - Region erase: finger wipe removes ink near the wiped area ("near" tuned experimentally with the user). - Whole-page erase: single diagonal finger stroke (upper-right → lower-left). - Provide stylus fallbacks if finger/stylus separation proves unreliable. ### Phase 4 — Toggle to/from the standard GUI *(necessary)* **Status (2026-06-26): BIDIRECTIONAL toggle works on-device (verified).** - **Chatter → standard:** top-left **"Back"** button → `AppControl::returnToStandard()` → transient unit stops chatter, starts xochitl. - **standard → Chatter:** a persistent **launcher daemon** (`tools/chatter_launcher.c`, installed as a rootfs systemd service via `scripts/install-launcher.sh`) watches the touch device and, on a **4-finger hold (~700 ms)** while xochitl is in front, runs `to-chatter.sh` to switch to Chatter. Gesture is tunable; finalize the memorable one with the user. - **Deployment note:** `/etc` and `/run` are volatile overlays (wiped on reboot); persistent installs go to `/home` (app/binaries/scripts) or the rootfs (`mount -o remount,rw /`, lost on OS update). Disable OS auto-updates on a delivered device. - A gesture/button in Chatter hands off to the standard reMarkable GUI. - A **memorable** mechanism returns from the standard GUI to Chatter. The proposal asks that the user help choose this; we will prototype options and let her pick. - **Phase 1 insight:** because the display is DRM/KMS (single master) and xochitl owns it while running, the toggle is a **hand-off**, not an overlay — stop/pause `xochitl` to give Chatter the display, and reverse to return. Mechanism (`systemctl stop/start` vs. `SIGSTOP/SIGCONT`) to be validated. ### Phase 5 — Save the page *(provisional — pending confirmation it matters to the user)* - A single visible button saves the current page. - Filename fully derived from date/time (year, month, day, hour, minute, second). - Written into a folder named **"Chatter"**, using the same on-disk document format the stock app uses, so transcripts appear as normal notebooks and can be renamed/deleted/synced via the standard GUI (see §6). ### Phase 6 — Field test & refine Matt installs and observes the user. Capture especially the "Why does this…" and "Why doesn't this…" questions; feed them back into this document and the phase plan. --- ## 5. On-device investigation checklist (Phase 1) These are the open questions the hands-on phase exists to answer. - **Input devices:** which `/dev/input/event*` is the pen vs. the capacitive touch; event format, coordinate range and orientation, pressure; the flip-to-erase signal on Marker Plus. - **Display:** how the color Gallery 3 panel is driven — framebuffer device and pixel format, and the refresh mechanism (ioctls or this model's equivalent). *(Highest-risk unknown.)* - **Document store:** where Xochitl stores notebooks; the `.metadata` / `.content` / per-page `.rm` layout for this model; the `.rm` format version (newer, color-capable); how a *collection* (folder) is represented; and whether a hand-built document appears in the library after a restart/sync. - **Coexistence & toggle:** how to launch our binary alongside / over Xochitl, and what a reliable toggle and return-to-Chatter mechanism looks like. --- ## 6. The "save" approach (clarification) reMarkable exposes **no public callable on-device API** for creating notebooks. The stock app simply **writes files to an on-disk document store** in a specific format (roughly: a UUID per document, a `.metadata` JSON, a `.content` JSON, and one binary `.rm` line-file per page, plus the color/folder data and a sync layer). A "folder" such as the **Chatter** folder is itself a document of type *collection*. So "save using the same method the environment uses" means: **write our canvas into the exact on-disk format Xochitl reads, for this model's format version.** The open question for Phase 5 is confirming/replicating the Paper Pro Move's current `.rm` format. This is investigated in Phase 1. --- ## 6a. Confirmed device facts (from SSH, 2026-06-25) - **Internal codename:** "Chiappa" (`/proc/device-tree/model` = "reMarkable Chiappa"; hostname `imx93-chiappa`). This is the Paper Pro Move (RM03A). - **SoC:** NXP **i.MX93** (Arm Cortex-A55). Relevant to the toolchain target and to how the display is driven. - **OS:** Codex Linux **5.7.121** (Yocto **scarthgap**), image version `3.27.1.0`. - **SSH server:** **dropbear** (not OpenSSH). Root login; `~/.ssh/authorized_keys` honored. Wifi SSH enabled via `rm-ssh-over-wlan on`. - **Access from Jatke:** passwordless via ed25519 key as `root` over wifi (the tablet's IP) or `root@10.11.99.1` (USB, fixed on every reMarkable). The tablet's actual IP/MAC and credentials are in `tablet_access.md` (SENSITIVE, gitignored). **Phase 0 status:** access established (dev mode, SSH over USB + wifi, key-based login, scp verified). Remaining for Phase 0: stand up the cross-toolchain and run a trivial ARM binary on-device. ## 6b. Toolchain / build & deploy (researched 2026-06-25) **Official SDK (cross-toolchain + Qt 6.8.2 sysroot), self-extracting `.sh`, x86_64 host only.** For this device (codename **chiappa**): ``` https://storage.googleapis.com/remarkable-codex-toolchain/3.27.0.97/chiappa/remarkable-production-image-5.7.119-chiappa-public-x86_64-toolchain.sh ``` - ~486 MB. Device image is `3.27.1.0` (Codex 5.7.121); newest published Chiappa SDK is `3.27.0.97` (5.7.119) — same `3.27.x` family, so binaries built against it run on the device. (An aarch64-host variant also exists; we use x86_64 for Jatke.) Download links live on developer.remarkable.com/links; the GCS bucket itself is not directly listable (403). - Build host **Jatke** (x86_64, ample disk). SDKs expect a Yocto-supported Linux host. **Install & activate:** ``` chmod u+x remarkable-production-image-5.7.119-chiappa-public-x86_64-toolchain.sh ./remarkable-production-image-5.7.119-chiappa-public-x86_64-toolchain.sh -d source /environment-setup-cortexa55-remarkable-linux # exact filename confirmed post-install (i.MX93 = Cortex-A55) ``` **Build a Qt Quick app** (per developer.remarkable.com/documentation/qt_epaper): CMake with `find_package(Qt6 REQUIRED COMPONENTS Quick)` + `qt_add_executable` / `qt_add_qml_module`; `cmake . -B build && cmake --build build` after sourcing the SDK env. **Deploy & run on device:** ``` scp build/ chatter:/home/root/chatter/ # deploy under /home, not rootfs ssh chatter 'systemctl stop xochitl' # release the display (pre-authorized) ssh chatter 'cd /home/root/chatter && QT_QUICK_BACKEND=epaper ./ -platform epaper' ``` Constraints (official + Phase 1): **Qt Quick/QML only, no Qt Widgets**; **xochitl must be stopped** (DRM single-master); **touch is automatic, pen is custom** (read `event2`). Some SDK/OS combos require copying `libqsgepaper.so` to the device — verify during the spike. ## 7. Decisions & open questions **Decided (from Phase 1):** - **Implementation stack: C++ / Qt 6.8.2**, rendered via the device's **`epaper` QPA plugin** (`-platform epaper`). Chosen because the stock app proves this path works and gives us e-ink display + refresh for free; the older fbdev-mmap approach is not available (DRM/KMS only). Cross-build with a Yocto scarthgap aarch64 SDK matching Qt 6.8.2. *(Matt — flag any objection.)* - **Deploy location: under `/home`** (45 GB free), never the rootfs (~88 MB free, overlay, reset by updates). - **Toggle is a display hand-off** with xochitl (see Phase 4), not an overlay. **Still open:** - **Save mechanism** — leaning **PDF-backed document** over authoring native v6 `.rm`; decide in Phase 5 (and gated by whether save matters to the user). - **Whether "save" matters to the user** — learned from observation. - **Toggle gesture + return-to-Chatter mechanism** — prototype and choose with the user (Phase 4). - **Erase "closeness" thresholds** — tuned experimentally with the user (Phase 3). --- ## Changelog - **0.6 (2026-06-26)** — Inking engine working on hardware: custom evdev pen reader (`event2`) + `QQuickPaintedItem` canvas — pen draws, eraser erases, finger-tap **Clear**, good latency. Added top control bar (**Back** left, **Clear** right); Back hands off to the standard GUI (verified). Bound the private `EPScreenModeItem` (key-function trick) to control panel refresh mode — but the **dashed two-pass stroke refresh is the render loop's behavior, independent of mode**, so it's deferred to a framebuffer-direct effort (needs disassembly of `swapBuffers` for `EPContentType`/`UpdateFlag`). Implemented **pen-style matching**: Chatter reads the standard GUI's selected pen (type/size/color) from `xochitl.conf` `LastWritingTool` and applies width + color — verified (Calligraphy, size 3, black). - **0.7 (2026-06-26)** — ⭐ **Solved stroke quality with a direct-framebuffer ink pipeline.** After proving Qt Quick can't render stock-quality e-ink strokes (geometry nodes unsupported by the software backend; painted-textures always get the dashed two-pass; screen-mode and antialiasing irrelevant), switched architecture: `FbCapture` interposes `EPFramebuffer::setBuffers` in-process (`-Wl,--export-dynamic`) to capture the real framebuffer image; `InkEngine` draws strokes straight into it and refreshes each segment with an explicit `swapBuffers` — **solid, crisp, low-latency, correctly-aligned strokes on hardware (verified), plus working Clear.** Qt Quick now only renders the static Back/Clear UI. Key RE findings: `swapBuffers` renders solid (not dashed) on a single explicit call; intra-DSO calls aren't LD_PRELOAD-interposable but the cross-DSO `setBuffers` is. Remaining: calligraphic nib (uniform round width vs the angled direction-dependent Calligraphy nib), return-to-Chatter trigger, Save, field testing. - **0.5 (2026-06-25)** — Phase 2 spike: cross-built a Qt Quick hello-app with the Chiappa SDK and rendered it on the e-paper via `-platform epaper` (proven on hardware). Recorded lessons (panel flock singleton, run-as-systemd-service, explicit Window size) and added `scripts/build.sh`, `deploy-and-run.sh`, `restore-xochitl.sh`. Seeded the source tree (`CMakeLists.txt`, `src/main.cpp`, `qml/Main.qml`). - **0.4 (2026-06-25)** — Researched the toolchain (§6b): identified the official Chiappa SDK (`3.27.0.97` / Codex 5.7.119, x86_64 host, ~486 MB), install/ activate steps, the Qt Quick build + `-platform epaper` run commands, and the deploy-and-stop-xochitl flow. Confirmed Qt-Quick-only + custom-pen constraints. - **0.3 (2026-06-25)** — Phase 1 on-device investigation substantially complete (see `Chatter_phase1_findings.md`). Resolved the stack decision to C++/Qt 6 + `epaper` QPA plugin; recorded display = DRM/KMS only, pen/finger as separate evdev devices, toggle = display hand-off, deploy under `/home`, and the document-store format for the Save phase. - **0.2 (2026-06-25)** — Phase 0 access established. Added confirmed device facts (§6a): codename "Chiappa", NXP i.MX93 SoC, Codex Linux 5.7.121 (scarthgap), dropbear SSH, passwordless key access from Jatke. Corrected the dev-mode menu path and documented that wifi SSH is off by default (`rm-ssh-over-wlan on`). - **0.1 (2026-06-25)** — Initial version: scope, target device (RM03A) and its constraints, roles, phase plan (with Toggle before Save), Phase 1 investigation checklist, save-format clarification, and open decisions.