The first complete writeup
Full control of the Freewrite Traveler
The Freewrite Traveler is a lovely e-ink typewriter; I bought mine to write offline, with no browser to tempt me. One odd thing: everything you type on it gets mirrored to the Postbox cloud — the maker's servers. You can't add your own fonts or change the layout. Yet inside, if you open it up, it's an ordinary Linux — Debian 10 on an i.MX6. Just locked from the outside. So we climbed in: got persistent root over SSH, took the app apart, rewrote it to suit ourselves. Here's exactly how. Honestly and in full — both what worked and what didn't.
01 — Context
What this is and why
Straight up: I'm not a programmer. At all — I work in communications and had never touched code before this. Everything described here we did together with Claude (Anthropic's language model): I explained what I wanted and what I saw on the Traveler's screen, it wrote the commands and code, I ran them on my end and reported back. So the «we» from here on is the honest word for it: I explained and tested, Claude wrote and prompted. The two of us climbed in together.
The Traveler is sold as a "distraction-free typewriter": e-ink screen, mechanical keyboard, no browser. But the idea comes with a lock. Everything you write is mirrored to the Postbox cloud (Astrohaus servers). Locally the drafts do stay, by the way — but inside a database you can't just copy out as files. You can't add your own fonts. The layout is whatever they gave you. And the day that cloud shuts down, the machine turns into a brick that "searches for a connection." (That exact line, in fact, once greeted me mid-trip — a slightly sad sight.)
I wanted to give the device back what should already belong to its owner: full access to its own Linux. Real root — the kind that survives reboots and writes straight to the root filesystem, not an SDK sandbox and not a "developer mode".
About that word, "first" — honestly, no fanfare. We're not the first to look inside. Back in October 2022 a user named machinaut posted a full serial boot log of the Traveler on Pastebin — so people were on the UART console years before us, and it's the very same hardware: i.MX6, Debian 10. In January 2024 Dr Francintosh (blog) opened the machine — but only to fix the keyboard, signing off that he'd "likely try to figure out how to reprogram" it. No root, no code of his own. There may well be a writeup of the root itself, close to ours, somewhere; if a precise link turns up, I'll add it here with respect. But a complete, reproducible account — how to reach persistent root and rebuild the firmware to suit yourself — I never found, however hard I looked. So "first" here is a modest word: it's about the whole recipe, not about us being uniquely clever.
This voids the warranty and can brick the device. Everything below is about your hardware, at your own risk. We don't flash the bootloader or kernel (see "Anti-brick"), so the risk is manageable — but real. Don't do this to a machine you're not ready to lose.
02 — Hardware & software
Inside the device
Under the pleasant shell sits a perfectly ordinary embedded Linux computer. That is the whole key: once you're inside, it's just Debian from there.
- SoC: NXP i.MX6SLL rev 1.1 (ARMv7, USB-OTG node
0x02184000), 512 MiB RAM. - Bootloader: U-Boot 2018.03 (built Sep 2020). Device-tree model: "Astrohaus Freewrite Traveler."
- Kernel: Linux 4.14.98 (Buildroot 2019.08).
- Userland: Debian 10 with systemd, OpenSSH 7.9.
- Application: "finchley" — Electron 2.0.7 (Node.js + React/Draft.js), running as the unprivileged user
finchley. - Database: PostgreSQL 11, cluster
ast_v1, databasefreewrite— this is where drafts, folders, the user and sessions live. - Screen: e-ink via the
mxc_epdc_fbcontroller, framebuffer/dev/fb01024×1536, physically split by a bezel into a large writing canvas (≈600 px in CSS units) and a narrow status strip (≈156 px). - Wi-Fi: the
eagle_sdiochip, compiled into the kernel (not a module), 2.4 GHz only, staged "eagle" firmware. - OTA updates: Mender (A/B partitions). There is no public DFU/USB mode on the Traveler — firmware arrives over Wi-Fi only.
Disk partitions
| Partition | Mount | FS | Note |
|---|---|---|---|
| mmcblk1p4 | / | ext4 rw | root, 2 GB — edits persist |
| mmcblk1p5 | /data | ext4 | data, 1 GB (sync/journal) |
| boot1 | /memristor | ro | boot hooks |
| mmc0 p0 | — | FAT | testjig, first files |
03 — Why it's hard
The locks on the door
Astrohaus closed the obvious doors. Understanding these locks saves hours — you immediately know what will not work.
- Zero boot delay.
bootdelay=0— "Hit any key: 0." The window to interrupt U-Boot is nearly nonexistent; the key must already be held at power-on. - Secure Boot (HAB) is closed.
HAB Config 0xcc / State 0x99. You cannot load your own U-Boot or kernel over serial-download (SDP) — the signature check will reject it. - No login on UART. The serial console prints boot logs, but no getty/login is running there — it won't just hand you a shell.
- No public recovery. The key combo for the Traveler's fastboot/recovery is undocumented — we later worked it out ourselves (E + X + L, see below); the factory reset wipes data.
The loophole that unlocks everything: HAB most likely covers only the bootloader and kernel, not the root filesystem. That means the kernel will boot with whatever arguments we hand it at runtime — including init=/bin/sh. Nothing needs flashing — for a single boot we just swap init and write our own key into the rootfs.
04 — Disassembly
Opening the case
The teardown is simple and non-destructive.
- Peel off the rubber feet.Six screws hide underneath, on the base.
- Remove the six screws.Standard Phillips; keep them apart.
- Disconnect the USB-C ribbon.The two halves then separate freely.
The board (barcode 202102251688 ≈ 2021-02-25, marking 7221A) is black, littered with labelled test points TP1–TP113+. The blue FFC connector J3 is the screen and keyboard, not UART.
Where UART lives
The prime candidate is a row of six through-hole pads in a line near the barcode (with resistors R58/R60/R62, R82, R111–114 nearby). There are no TX/RX/GND labels — you work out the pinout yourself. In practice it turned out to be:
- GND — the rightmost pad (the square pad = "pin 1").
- Board TX — second from the left.
- Board RX — adjacent to TX.
How to find it if your revision differs: GND — continuity-test each pad against bare metal (the USB-C shell or a screw). TX — listen with your adapter at 115200, tie the grounds together, and rotate the adapter's RX across the pads while powering the device on: wherever the boot log appears is TX. RX — the neighbour.
What you'll need
- a small Phillips screwdriver and a thin plastic spudger
- a 3.3 V USB-UART adapter (we used an FT232RL; the level jumper on 3.3 V, not 5 V, or you can damage the SoC)
- a multimeter in continuity mode — to find GND
- a soldering iron optional: the pads are through-hole, you can also just press pins in
A map of the board
The revision we opened: barcode 202102251688 (≈ 25 Feb 2021), marking 7221A. The board is black and literally littered with labelled test points TP1–TP113+. Don't be fooled: the blue FFC connector J3 is the screen-and-keyboard ribbon, nothing to do with UART. The row of six through-hole pads you want stands on its own line by the barcode, ringed by resistors R58/R60/R62, R82, R111–R114. It has no silkscreen labels — re-check the pinout from the UART section against your own board with a multimeter: revisions can differ.
Don't look for a reflash path here. With the board in front of you it's tempting to load your own image over SDP. It won't work: Secure Boot is closed (see "What didn't work"). The one working gate is UART → U-Boot — that's where we head.
05 — Serial console
The UART console
You need a 3.3 V USB-UART adapter (we used an FT232RL with the jumper set to 3.3 V). Speed 115200 8N1. Wire GND↔GND, board-TX→adapter-RX, board-RX→adapter-TX.
A logger on the Mac that survives the whole process:
# log everything to a file so the boot log can be grepped screen -L -d -m /dev/cu.usbserial-XXXXXXXX 115200 # watch: tail -f screenlog.0 (binary junk at the start, use grep -a)
Reliable boot capture. A cold start yields the full U-Boot log and Reset cause: POR: first power off (new+Power ≈3 s), then power on (Power). A "15 s Power hold" doesn't always give POR.
From the log you'll see what we saw: U-Boot 2018.03, i.MX6SLL, 512 MiB, model "Astrohaus Freewrite Traveler," then the kernel and systemd, the PostgreSQL cluster ast_v1, a Vector service, the "Smart Typewriter frontend." U-Boot also prints the scan code of any key held at power-on — "Detected N keys for recovery: Key XX."
What the boot log tells you
The first full boot log already tells you most of what you need to know about the system. Here are the lines worth capturing it for, and what each one means:
| Line in the log | What it means |
|---|---|
| U-Boot 2018.03 (Sep 2020) | the bootloader; also where bootdelay=0 lives |
| i.MX6SLL rev1.1 · 512 MiB | the SoC and RAM |
| Model: Astrohaus Freewrite Traveler | the device-tree name |
| HAB Config 0xcc / State 0x99 | Secure Boot closed — no custom image |
| env ... bad CRC | the MMC environment is corrupt → the default is used |
| Reset cause: POR | a cold boot was captured (what you want) |
| Detected N keys for recovery: Key XX | the scan code of a key held at power-on |
| Linux 4.14.98 (Buildroot 2019.08) | the kernel |
| PostgreSQL cluster ast_v1 | where your text lives |
| Vector · Smart Typewriter frontend | the app's system services |
Note env ... bad CRC: the on-disk U-Boot environment is corrupt, so the loader falls back to its compiled-in default — another reason you can't rely on saveenv, and why the init= override is done "live" only.
06 — The core of it
Getting root
The idea — "Path B": flash nothing; for a single boot, make the kernel launch a plain shell instead of the system (init=/bin/sh), get it as root, remount the root read-write, and plant a permanent way in. HAB permits this: it doesn't validate kernel arguments, and the rootfs is unsigned.
First: how to interrupt the bootloader at all
The crux is bootdelay=0. U-Boot doesn't wait: the "Hit any key to stop autoboot: 0" line flies past in microseconds, faster than a human can press. The trick is to not "press at the right moment," but to have a keystroke already sitting in the UART receive buffer when U-Boot reaches that check. In practice: start holding a key (or streaming characters) in your terminal a heartbeat before you apply power. One of them lands in the micro-window — autoboot stops and the => prompt appears. The trick isn't reaction speed but a buffer that's already loaded.
The exact moment of access
Now the most important — and simplest — part, the one that usually gets lost in explanations. We don't exploit anything and don't crack a password. We tell the bootloader one thing: "run this program instead of the system" — and hand it init=/bin/sh. The kernel boots as usual, but its first and only process (PID 1) is not systemd (which would have brought up the password login) but a bare /bin/sh. And PID 1 runs as root (uid 0) by definition, and a bare shell has no password prompt.
Where root actually appears. The instant a # prompt appears on the UART after boot — you are already root, with full read/write over the entire disk. No password, no exploit: you simply told the bootloader to skip the login system and hand you a root shell. Everything after that (the key, the password) is only cementing the access you already have, so it comes up by itself after a normal reboot.
Why Secure Boot (HAB) doesn't stop this. HAB signs images — the bootloader and the kernel. But it checks neither the arguments you pass the kernel (init=…) nor the filesystem it mounts. We changed not a single byte of the signed images — we only changed how the signed kernel is invoked, for one boot. That is exactly why "you can't flash your own U-Boot, yet you can still get root."
Step by step
- Interrupt U-Boot.Because of
bootdelay=0, spam a key in the terminal exactly as power is applied, until the=>prompt appears. - Override init at runtime — without saving.Critically: do not run
saveenv. We change the environment for this boot only. - Boot into a single-user root shell.The kernel hands you
/bin/shas root, no password. - Remount rw and plant your way in.Your ssh key into
/root/.ssh/authorized_keys, set a root password, unlock root in/etc/shadow. - Sync and reboot normally.After a normal boot, key-based login comes up on its own.
# at the U-Boot => prompt (do NOT save the environment!) => setenv bootargs ${bootargs} init=/bin/sh rw => boot # we're in a root shell. remount the root read-write: # mount -o remount,rw / # your public key (one line, no wrapping): # mkdir -p /root/.ssh # echo "ssh-ed25519 AAAA...your_key..." > /root/.ssh/authorized_keys # chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys # backup root password + unlock the account: # passwd root # sync # reboot -f
UART mangles pastes. This serial console drops multi-line pastes and lines with quotes (it will eat a ' and hang on >, or wedge junk into the password). The rule: send one short line at a time, and verify by reading the actual file (cat/grep), never by the terminal echo. Do all the setup in the live shell before the reboot — there a typo is one command to fix; after the reboot it isn't.
Persistence confirmed. The root /dev/mmcblk1p4 is ext4 rw, so the key, the password and every later edit survive reboots (verified: fresh boot, key in place, login came up by itself). This is FULL root, not an SDK sandbox.
07 — Dead ends
What we tried that didn't work
The road to root was not straight. Here are the dead ends — honestly, in order. Each one saves you time: don't go there.
✗ The single SDK login over SSH
The first thing you try on a plugged-in device is SSH. It brings up a USB gadget, but only tcp/22 is open, and the documented sdk:sdk over IPv6 link-local answers Permission denied. Guessing passwords is pointless and harmful — the device has a classifier that kills brute force; only single documented logins get through.
✗ The sanctioned SDK & extensions
Freewrite has an official developer path (the garnet SDK): a static IPv4 (192.168.99.44 → .190), sFTP sdk:sdk, an extensions/ folder, and "Preflight" JS hooks that run before a document is uploaded to Postbox. It's useful (you can intercept/encrypt/route a draft), but it's a sandbox: a different user, not root, no access to the filesystem or the system. For full control, that isn't enough.
✗ Flashing our own bootloader/kernel (SDP)
The i.MX6 supports serial-download (SDP) — so, seemingly, flash your own U-Boot and do as you please. No: Secure Boot HAB is closed (HAB Config 0xcc / State 0x99), and an unsigned image is rejected. That is exactly why we don't flash — we go around it through kernel arguments (see "Getting root").
The recovery combo: guessing failed, so we reverse-engineered it
At boot U-Boot prints the scan code of a held key: "Detected N keys for recovery: Key XX." We tried single keys — 35 (;), 39, 42, 61 — all "Fastboot: Normal." Dead end: the entry turned out to be a multi-key combo, and nobody had published which one. So we came at it from the other side — pulled U-Boot straight off the device (/dev/mmcblk1boot0), worked out the load address from the IVT header (0x877ff000), disassembled it in radare2, and found the function. It builds a three-bit tally: one key from each of three groups — and if all three are held, it boots the recovery kernel (a fourth key, by contrast, throws it into panic). The scan codes spelled E + X + L — the same chord as the factory reset on the sibling Freewrite Alpha. So the Traveler's recovery is E + X + L, held at power-on. We already had root by then, so we didn't need recovery — we just wanted to close the question.
✗ Small false trails
- "Hold Power 15 s" to restart — does not always give a clean POR log. Only a full power-off (new+Power ≈3 s) then power-on is reliable.
- "The device doesn't serve DHCP." At first the Mac took an APIPA
169.254.xand we assumed there was none. In fact the device does bring up DHCP itself (the Mac gets.44, the device.190). A false alarm.
08 — Permanent way in
Access over USB-C
Plugged into a computer, the Traveler brings up a USB-C network gadget. The Mac gets an interface (ours: en8), and the device serves DHCP itself: the Mac takes 192.168.99.44, the device is 192.168.99.190, with SSH open on tcp/22. The address lives as long as the cable is in.
Host freewrite
HostName 192.168.99.190
User root
IdentityFile ~/.ssh/freewrite_ed25519
StrictHostKeyChecking accept-new
$ ssh freewrite root@59a291782d3941d7:~# # full root — from here on it is just Debian.
The device sleeps aggressively. The baker-powerd daemon drops the USB bridge after about two minutes of idle — SSH disconnects. systemctl stop powerd keeps it awake (reversible with a reboot); or simply work fast and wake it with a keypress. After a drop, wake the device and en8/.190 return by themselves.
09 — How it fits together
System map
The application is called finchley and lives in /astrohaus/finchley/. Understanding its two halves saves enormous time.
- Main process —
core/andmain.js. Plain Node.js, required at runtime. Editcore/*.js+ restart finchley and the change is live, no rebuild. - Renderer —
sdk/ui/(React), compiled intodist/bundle.jsby webpack. Any UI change requires a rebuild (see §09). - Launch: the systemd unit
finchley.service(restart withsystemctl restart finchley.service). Power and sleep are handled bypowerd.service(thebaker-powerddaemon).
Where the text lives
Drafts live in PostgreSQL (database freewrite, 127.0.0.1:5432). The key table is document (uuid, title, body, uploaded, uploadedAt, folder_id, createdAt…). There's also folder, user, session, printjob, device_shred_jobs. Access is via the postgres system user:
# su - postgres -c 'psql -d freewrite -tA -c "SELECT uuid,title,uploaded FROM document;"'
Your text stays on the device — in this very database. The stock sync daemon /astrohaus/highgate/ (compiled to .so via Cython) mirrors drafts to postbox.getfreewrite.com and sets an uploaded flag. But it doesn't wipe them locally: a document row disappears only when you yourself shred or archive a draft — that's when a device_shred_jobs entry shows up. So there is somewhere to pull your writing from, which is exactly what we did (see §10).
The table schema
| Table | Key columns |
|---|---|
| document | uuid · id · title(≤50) · body · uploaded · uploadedAt · folder_id · bookmarked · createdAt |
| folder | folders A/B/C (folder_id 1/2/3) |
| user | font_size · languages[] · is_tooltip_shown · ... |
| session | session / user |
| printjob | print jobs |
| device_shred_jobs | shred/archive queue — only on your explicit action |
✓ The text is stored here, in document, and survives reboots. It's mirrored to Postbox (uploaded/uploadedAt), but stays locally — gone only on your own shred or archive. So there is something to pull off the device: our sync reads the .md straight from here.
The sync daemon — "highgate"
The upload logic lives in /astrohaus/highgate/ and is compiled to .so via Cython (highgate.so, fota_*.so, setup.so) — hard to read or patch directly. Endpoints: postbox.getfreewrite.com (drafts) and repo(-traveler).astrohaus.com (FOTA). Takeaway: rewriting sync is easier not inside the .so but by intercepting at the hosts/DNS level, disabling daemons, or via an SDK extension — which is what we did (see "What we changed").
Inside finchley
main.js+core/— the main process: Sequelize models, dbus, daemons. Edit + restart = live, no rebuild.sdk/ui/— the renderer (React); webpacked intodist/bundle.js. Fonts live here too asdist/*.ttf.preload.js— the Electron bridge;core/extensions— built-in hooks;/data/freewrite/extensions— user (SDK) ones.- Device settings:
/data/freewrite/config/settings.json.
10 — Your own UI changes
Rebuilding the app
The renderer is a webpack bundle, so "change a button" means rebuild. It's convenient to build right on the device, from a copy of the source. On the weak i.MX6 a build takes ≈8 minutes.
# 1. a working copy of the source # cp -r /astrohaus/finchley /data/fbuild # cd /data/fbuild # 2. babel/webpack environment (once) # printf '{ "presets": ["react","env"] }' > .babelrc # npm install --ignore-scripts # 3. edit sdk/ui/... then build (~8 min) # NODE_ENV=production ./node_modules/.bin/webpack \ --config webpack/webpack.config.prod.js # 4. deploy the bundle and restart # cp -r /data/fbuild/dist/* /astrohaus/finchley/dist/ # chown -R finchley:astrohaus /astrohaus/finchley/dist/ # systemctl restart finchley.service
File ownership. The app runs as the finchley user (not root). Files are owned by finchley:astrohaus. If you copy from a Mac over scp (as root), you must chown finchley:astrohaus afterward — otherwise the app can't read its own bundle. Keep a bundle.js.bak before each deploy.
11 — In practice
What we changed
With root, the device becomes yours. Here's what we've already done — a map of what's possible.
→ Our own sync instead of a dead cloud
We disabled the cloud daemons (commented out document_uploader, settings_downloader, sync_shredded in core/daemons/index.js) and wrote our own sync on the Mac side: once a minute a launchd agent reads the document table over SSH, turns each draft into a .md file, and drops it into a working folder + Obsidian. The text no longer goes to someone else's cloud; it stays on your own Mac.
→ A Russian keyboard
The ru layout already existed in the keyboard engine but was disabled: the user's languages field in the DB was empty. One SQL line, and Ctrl+Shift cycles languages, with the built-in indicator.
=> UPDATE "user" SET languages = ARRAY['en','ru'];
→ A road mode without the cloud
To collect drafts on the road, the device brings up its own access point (hostapd + dnsmasq) and serves the drafts as a web page at http://10.42.0.1. The phone joins the "Freewrite" network and sees everything written. The firmware shipped without dnsmasq/hostapd/iptables — we had to sideload them (verified .debs from archive.debian.org over HTTPS+SHA256, since apt has no sources).
→ A clock that doesn't lie
The Traveler's RTC has no battery — powered off, it loses time. We keep it in sync three ways: a launchd agent on the Mac sets the time every 60 s over USB; NTP when online; and a nudge from the phone on the road (the export page posts /settime?ts=…).
→ The interface, made ours
- Removed all "Freewrite/Astrohaus" branding from visible surfaces.
- A permanent status panel on the lower screen (folder · words · time · battery · sync · language) instead of paged widgets.
- A font-size switcher right in settings (keys 1/2/3), persisting to the DB through a core service.
- Killed the LED that shone through the case (an RGB lamp under
/sys/class/leds).
→ Deep-writing modes
Since it's an offline instrument for depth, we added two modes for the act of writing itself. Fade: old text on the e-ink dissolves into fog, only the last lines at the cursor stay sharp — forward only, the Freewrite philosophy taken to its limit. Immersion: instead of a word count, a metric of the longest unbroken flow (how long you wrote without ever pausing more than 90 seconds).
Under the hood: moves worth stealing
Three mechanisms from our changes that generalise to anything on this device.
1. Writing to the DB as the app, not as root.
The renderer runs as finchley and can't su postgres. A live change goes through Redux + a core service (persist), not straight to psql:
// live: Redux -> re-render Paper this.props.actions.updateUser({...user, font_size: size}); // persist: core service via remote require('electron').remote .require('./core/service/user') .setFontSize(user.id, size); // models.User.update(...)
2. Testing connectivity without ping.
There's no ping binary — do all diagnostics through bash's built-in /dev/tcp (or you'll get a false "no network," as we once did):
# timeout 4 bash -c 'exec 3<>/dev/tcp/1.1.1.1/443' && echo UP || echo down
3. "Deep writing" — a mask on the textarea.
Fading old text is a CSS gradient mask on the <textarea>: transparent at the top edge, sharp at the cursor. No editor-engine changes:
maskImage: 'linear-gradient(to bottom,' 'transparent 0%, #000 14%, #000 100%)'
Immersion (the longest unbroken flow) is measured from keystroke timing in a global keydown: a pause over 90 s breaks the flow, over 20 min starts a new session. All ordinary React in the renderer, available after a rebuild (§10).
12 — Map of the rakes
Reference & gotchas
Small things, each of which cost us an hour. Take them for free.
| Rake | What to do |
|---|---|
| ping | it does NOT exist → test connectivity with bash /dev/tcp/host/port, not ping |
| curl | also absent → fetch .debs from a host and dpkg -i |
| baker-powerd | drops USB after ~2 min → systemctl stop powerd or work fast |
| /tmp | clears on sleep — don't keep anything you need there |
| UART paste | mangles quotes & multi-line → one line at a time, verify by reading the file |
| sudo | stock binary lacks setuid ("broken") → chmod 4755 /usr/bin/sudo |
| renderer | runs as finchley (non-root): no su postgres → write to the DB via a core service/sudoers |
13 — Safety net
Anti-brick
The main reason this path is relatively safe: we never flash the bootloader or kernel. All edits are in the rootfs, which is reversible. Broke a file — restore it from backup through the same root access.
- Always back up a file before editing it (
cp x x.bak). - Don't touch
saveenvin U-Boot — change the environment for one boot only. - Last resort: the i.MX6 supports serial-download (SDP). Recovery via
imx_usb_loader/uuu(mfgtools). ⚠️ but HAB is closed — you can't load your own unsigned image this way, so protect the rootfs rather than counting on a reflash.
14 — The human side
What we found along the way
When you climb inside a locked device, you meet not just its locks but the people who built it. Here are three finds about them.
Codenames — London Underground stations
The system's components are named after London Underground stations — a quiet signature of the team, visible only to someone who climbed inside.
| Component | Role | Tube |
|---|---|---|
| finchley | the app (Electron) | Finchley |
| highgate | Postbox sync daemon | Highgate |
| baker-powerd / -paperd | power & screen | Baker Street |
| brixton | app service | Brixton |
The writer screensavers — the ones we turned off
On boot the device cycled portraits of writers — ink-and-watercolour, each captioned "set your story free." They are genuinely beautiful. We turned them off (on our panel they got in the way and flipped), but they're too lovely to lose — so here they are, published. In their place we put a Chronolith: at rest, the screen shows a literary quote that names the current hour. You glance at the sleeping machine, and there's a line from a book about exactly this time.
What we put in their place — and the idea behind it
We didn't just "switch things off." There was a single idea: turn a cloud-tethered gadget into a personal, offline deep-writing instrument that belongs to you. The writer screensavers are lovely, but on our re-oriented panel they flickered and flipped — so in their place we put something else:
- One permanent status line instead of switchable widgets: folder · words · time · battery · "Synced to your Mac" · language — always visible, always honest.
- A fade — old text dissolves at the top edge so you look forward, not back; and "immersion" — a meter of your longest unbroken flow of writing.
- Our own Mac-side sync instead of the dead Postbox cloud, a Russian keyboard, a font-size control, and an honest interface with nobody else's brand.
The through-line is simple: the machine serves the writing, and the writing belongs to you. The details of each move are in "What we changed."
Easter egg: a developer among the classics
In that same screensaver folder, among Poe, Dumas and Austen, sits a file called ginger.jpg — and it is not a writer. It's a candid photo of one of the developers: a ginger fellow with an enormous mug in a café, in a "TIDES" fleece. A quiet joke left inside the firmware — a wave from the people who wrote it.
We deliberately keep this easter egg in the document: it's part of the device's character. Taking control needn't be hostile to the people who built it. We took our typewriter back — but the fellow with the mug, we respect.
15 — Finally
Disclaimer & ethics
All of this is with your own device — the one you bought and own. Repairing, studying, changing what's yours is fine; it's your right. We don't hand out anyone's firmware, don't bypass DRM for anyone's content, and don't poke around in anyone else's hardware.
And still: rooting voids the warranty, turns off the vendor's cloud sync, and can cost you your data or the machine itself. No promises. Do it thoughtfully, with backups, on a device you wouldn't mind losing. Everything above is how we did it. If you repeat it, you do so at your own risk.
Why any of this. A good typewriter serves the person writing on it, not a cloud that will one day shut down. We gave the Traveler that simple thing back — you can do the same for yours.