← Experiments
03 · The desktop · Sept 2026

shellOSa single-window meta-OS shell · pure Bend

A desktop where every pixel is computed in Bend.

The same AI app builder wrote a whole shell: terminal tabs over a real PTY, an HTML reader, a command palette, search, Gmail and AI panes. The font rasterizer, the layout and the terminal emulator are pure Bend; only files, sockets, TLS, the PTY and the window sit behind a small C seam. It arrived as a zip for a Linux VM that couldn't build it. Claude Code ported it to a Mac, found three bugs its suites never caught, and redesigned it.

9,641
lines of Bend
17
C effect files
3
bugs its tests missed
2×
faster frames
Shell-OS
shellOS after the redesign: themes and saved panes, an items list, the reader, and a terminal showing ls -la, with a TERMINAL mode badge in the status bar
After · native macOS window · 1440×960
What it is
A whole desktop shell, rendered by a pure Bend program
The port
Linux VM to macOS: two build fixes, no app changes
The misses
State changed, screen didn't: three times
The redesign
TUI panes, a real font, twice the frame rate
01 — What it is

Pure, except the seam.

Every frame is a quadtree image built by pure functions. The program asks the outside world for exactly five kinds of thing, each through a named effect with a C file behind it. Everything else is data in, pixels out.

What's real

A live /bin/sh in each terminal tab and items saved with tmp + fsync + rename, both exercised here. HTTPS with mandatory certificate checks and owner-only Gmail and AI configs are built in but were not re-run here.

What's pure

Rendering, layout, font rasterization, the terminal state machine, HTML parsing, search. None of it can touch the outside world.

Honest limit. "Pure" describes the program, not the platform: the window, the Metal presentation and the GPU path are Bend's runtime, and the effect seam is ordinary C.
02 — The port

Written for a VM that couldn't build it.

The package arrived with a nine-step plan for a Linux VM. Step four, the native build, needed 5 GB of free memory the VM never had: for five days its hourly status runs deferred the rebuild, so the shipped binary predated its own bug fixes.

0

Lines of app code changed

Bend's window already has a native macOS backend and maps keys the same way on both platforms. The shell's Bend code ran as written.

2

Build fixes

Point the clang wrapper at Homebrew's OpenSSL, and replace Linux-only flock with a mkdir lock.

52 s

First native build

3.2 GB peak memory on the Mac; zero warnings after fixing four pointer-size warnings in the C seam. A 6.3 MB arm64 binary.

22

Gates per launch

A new harness drives the real window: keys posted to one process, screenshots of one window, fresh working dirs, exact PIDs.

The Linux harness drove a virtual X display. On macOS it's macwin, a small Objective-C tool: find the window by PID, post keys and clicks with CoreGraphics, capture with screencapture -l.

03 — What the suites missed

The state changed. The screen didn't.

The shell redraws only when something marks the frame as touched. Its test suites checked state: palette open, query typed, selection moved. They all passed. None of them looked at the pixels, and that is where all three bugs lived.

Bug 1 · first screenshot

The palette froze after it opened.

Typing a filter or pressing an arrow changed the palette's state, but only open and close marked the frame, so the old frame kept being shown. The builder's fix had covered open and close and stopped there.

Fix: move, type and backspace mark the frame. New probe t35 fails on the old code, passes on the fix.
Bug 2 · redesign screenshots

Help never appeared.

Pressing ? opened the help overlay in state and never repainted, so in the native app it was invisible. Its suite passed 14 of 14.

Fix: opening and closing help marks the frame. Two probes, red then green.
Bug 3 · the harness quit

Esc to close help also quit.

Help wasn't counted as an open panel, so keys went through it: the Esc that closed help reached the main keymap and quit the app, and d would have deleted an item underneath.

Fix: help counts as open for key stripping. Two probes, red then green.

All three were found by looking at real screenshots of the real window. A frame diff proves that something changed; only looking shows that the right thing changed.

04 — The redesign

Still a TUI. Now a legible one.

"Not very pretty or clean." Two directions were mocked up at pixel fidelity on the app's own canvas with its own bitmap-font drawing; the owner picked rounded panes with titles in the border. Then: "the fonts are REALLY small." The window maps one canvas pixel to one point, so on a scaled 6K display the fix was a bigger font on a bigger canvas.

Before
Shell-OS
The original shellOS: an 8 by 8 pixel font, grey boxes, large mostly empty item cards, a terminal cropped to 30 columns
font8x8 · 1024×1024 · terminal cropped to 30×30
After
Shell-OS
The redesigned shellOS with the command palette open, filtered to four tab actions with keycaps
Spleen 8×16 · 1440×960 · full 80×24 terminal
Panes, not boxes

Rounded borders with titles set into them, one accent color, a color per theme, three text weights, and "…" instead of clipped text.

A status bar with a mode

NORMAL, PALETTE, TERMINAL, READER: a badge and the keys that work right now. It becomes the input line when you add, edit or write a note.

Faster, not slower

Full-frame render went from 21 ms to about 11 ms. The old font walked a 1,024-entry list for every glyph row; the new one is a match.

The whole terminal

The old tile showed a 30×30 corner of an 80×24 grid. Now the full grid shows, and the shell is told its window size.

Shell-OS
Universal search over items, reader articles and terminal lines
Search: items, articles, notes, terminal
Shell-OS
The help overlay listing keys as keycaps, now visible
Help: invisible before bug 2 was fixed
Shell-OS
Saving an article with a note typed into the status bar
Save article: the note is typed in the status bar
Shell-OS
The terminal pane focused, showing ls -la output from a real shell
Terminal: a real /bin/sh behind a PTY
05 — Honest limits

What this doesn't show.

Untested panes

Gmail and AI were restyled but never run live: there were no configs on this machine.

Suites test state

All eight suites pass, 198 checks. They still test state, not pixels: the window harness and screenshots are what catch a screen that didn't change.

One machine

Every number here is from one Apple-silicon Mac, on Bend 2.0.34 and again on 2.0.35. The Linux build path was not re-run.

The builder's history

The shipped report logs ten days of work on the VM, starting 20 Sep. Only what was re-run here is claimed here.

06 — Bend 2.0.35

Re-verified on Bend 2.0.35.

Bend 2.0.35 shipped on 3 Oct. The shell built on it with no source changes. Because shellOS is all rendering, the test that matters is the screen: same pixels, same speed.

0 lines

Changed to build

./build.sh native succeeds on 2.0.35 in about a minute; the foreign-code verdict still lists the same 164 seam defs.

40 / 40

Window checks, two launches

The macOS harness drives the real window: palette, search, add, quit, relaunch and reload, in fresh working dirs.

=

Identical frames

The render benchmark's 4 MB output frame is byte-identical between the 2.0.34 and 2.0.35 builds. Timings and peak memory (156 MiB) match within run-to-run noise.

198 / 198

Suite checks, all eight suites

Five suites passed with identical counts on 2.0.34 and 2.0.35. The other three had stopped compiling long before; their fixtures now match the current types, and all eight pass.

The three benchmarks' build recipes still named the pre-redesign font file and no longer compiled on either compiler; they now name font8x16.bend.

The Bend series

One language. Three builds. One auditor.

Three programs, one young language, one method. Each was written by an AI app builder in Bend 2 under an evidence-first discipline, then handed to Claude Code to check: reproduce every claim, attack it, profile it, fix only what is proven, and show the fix changed nothing else. Every time, the builder's own tests passed, and something real was still wrong.

About the series: the language, the method, what it found →