WorldTUI Fine-Tunes a 360M Qwen Model to Fake a Linux Terminal in Your Browser
TL;DR
WorldTUI is a 360M-parameter language model that pretends to be a terminal. Nothing runs underneath: every keypress goes in, and the model predicts which screen rows change and where the cursor lands. Simon Edwardsson built it on top of Qwen2.5-Coder-0.5B with about 75 GPU-hours on one RTX 4090, quantized it to a 208 MB int4 file, and ships it as a WebGPU demo that runs locally in Chrome. It handles vim, tmux, man pages and a self-playing snake, and it remembers files you wrote a few commands ago in 9 of 13 readback tests. The write-up hit 638 points on Hacker News.
What it is
Edwardsson says he got the idea from Genie 3, DeepMind's world model that generates the next game frame from your inputs. He didn't have a cluster or a video corpus, so he picked a smaller world: a grid of characters. A terminal is cheap to simulate, perfectly labelled training data comes from running real shells, and a coding model has already seen plenty of ls output.
The question he wanted answered was whether a small model could keep a consistent world or would only produce output that looks right. Type pythoon into the demo and Python still launches, which tells you there's no real shell on the other end.
A terminal as a stream of screen edits
A chat model appends text to the end of a transcript. A terminal doesn't work that way: clear wipes the screen, vim repaints the whole window, and one Escape key changes modes without printing anything. So WorldTUI predicts edits to a grid, one keypress at a time.
A session opens with a snapshot (screen size, contents, cursor position). Each keypress goes in as the raw bytes a real terminal would send, so Enter is \r and the left arrow is ESC [ D. The model answers with row writes and a cursor position. Idle time arrives as a WAIT token, which is how snake keeps moving when you don't touch anything.
Two format choices do most of the work. A COPY operation moves a row from the previous screen, so scrolling costs three tokens per row instead of roughly 96, and the same trick covers clearing, vim line inserts and man page navigation. And the whole vocabulary is 333 tokens: 256 byte tokens reused for characters and coordinates, 64 row tokens, and a few operations. Decoding is grammar-constrained, so the model can't emit a malformed update.
Training data from Docker, and a model that fixes itself
Edwardsson couldn't find recordings with exact keystroke-to-screen alignment (he checked asciinema), so he generated his own. Docker containers with randomized usernames, hostnames, prompt styles and terminal sizes ran sessions for fictional personas, with 6 to 24 weighted activities each and simulated human typing at a 1.2% typo rate. 35% of sessions start mid-application. The final set was 336k episodes, roughly 2B tokens.
Plain supervised fine-tuning learned typing quickly but let errors compound: one misspelled filename poisoned the rest of a session. The fix borrows from DAgger. Let the model run 1-4 steps on its own, compare its screen with the recorded one, and if the gap is small, train it on a correction that repairs its own wrong screen on the next keypress. It's closer to teaching a driver how to recover from a wrong turn than drilling the perfect route a thousand more times.
A correction is only allowed when the right answer already appeared on an earlier real screen or in the user's typing. Training it to "fix" a filename it never saw would reward hallucination. Three rounds of this, plus more data, raised his PresetBench score from 24/47 to 38/47 at int4.
Making it fast: rows in parallel, then a referee
Token-by-token typing felt fine at about 38 ms per key on the 4090. A full redraw is around 3,000 tokens, though, and opening vim or man took up to 12 seconds. Edwardsson's way out: most rows in a frame don't depend on each other. Each row gets its own batch element sharing the same history and KV cache, so the cost drops from the sum of all rows to the length of the longest one, roughly 100 steps.
Independent rows can't coordinate, and it showed. Vim opened on row 3, and several rows added food to the snake game at once. So the parallel output became a draft, and the same model verifies it sequentially, keeping tokens up to the first disagreement and regenerating from there. Speculative decoding usually pairs a small drafter with a big verifier. Here the model checks its own work. Picture 32 painters each doing one stripe of a mural at once, and then one editor walking top to bottom and repainting from the first stripe that doesn't line up.
In the browser on an M4 Mac, a single character takes about 60 ms. Edwardsson notes the speculative trick helps far more on the 4090 than on the M4, and suspects the bottleneck moves between compute and memory bandwidth, which he hasn't confirmed.
Shrinking it to 208 MB
The base Qwen2.5-Coder-0.5B has about 494M parameters, and 136M of them sit in the embedding table for its 151,936-token vocabulary. WorldTUI only needs 333 tokens, so dropping the rest takes it to about 360M parameters. Int4 quantization brings the file to 208 MB. The demo runs a custom JavaScript implementation of the Qwen decoder with WGSL compute shaders over WebGPU that unpack the 4-bit weights on the fly.
The layer that holds the memory
The distillation detour is the most reusable finding in the post. Removing layer 7 alone, with no retraining, barely moved next-token accuracy (99.3% to 98.9%), but exact memory readbacks fell from 64/64 to 0/64, even with the true history fed in. A 16-layer student that kept layers 1, 7, 15 and 22 passed all 32 memory worlds, still did so at about 138 MB in 4-bit, and dropped from 78 to 65 on ShellBench. A student that kept every even layer guessed between the two values it had written, about half right. If you prune or distill a model, next-token accuracy can look healthy while the model forgets what you told it. Edwardsson eventually dropped distillation altogether.
What works and what doesn't
- Works: creating and editing files, vim mode switching and saves, multi-pane tmux, environment variables, man pages, and a snake game Edwardsson calls "probably the most compute-intensive snake in the world."
- Shaky: new combinations of familiar commands. After
echo green >> colors,cat colorsoften misses the appended line. Nested directories sometimes teleport you to a different path. - Weak: the Python REPL gets small additions right but returns list comprehensions with the wrong contents. There's no network, so text browsers are dull.
- Browser caveat: about 20x slower in Firefox than Chrome on the same WebGPU path, cause unknown. Weights are "coming soon"; today you get the demo, not a download.
He doesn't oversell it either. Asked whether it's useful, his own answer is "Not really." The interesting part is that a model this small keeps a partly consistent world without any of the rules coded in, and that the recipe (synthetic environment traces, a delta output format, self-repair training, parallel drafts with self-verification) carries over to any app you can record. His next experiment is training on thousands of randomly generated applications to see whether the model can predict one it has never seen.
If you're building agent sandboxes or cheap environment simulators, this is a small, fully documented reference implementation. It's also a fun way to lose ten minutes trying to break a terminal that doesn't exist.
Key Takeaways
- WorldTUI is a 360M-parameter fine-tune of Qwen2.5-Coder-0.5B that predicts terminal screen diffs from raw keypresses, with no shell behind it, in a 208 MB int4 WebGPU demo.
- A 333-token vocabulary with a
COPYrow operation and grammar-constrained decoding makes full-screen apps like vim and tmux tractable. - DAgger-style self-repair training lifted PresetBench from 24/47 to 38/47; the model scores 80/106 on ShellBench and 9/13 file readbacks against 60/106 and 3/13 for prompted Qwen3-0.6B.
- Parallel row decoding cut 4090 p95 redraw latency from 6.7 s to 0.87 s, and draft-then-verify fixes rows that can't coordinate.
- Pruning one layer kept next-token accuracy at 98.9% but erased memory readbacks entirely, so test recall directly when you distill.
- Training took about 75 GPU-hours on one RTX 4090 using 336k synthetic Docker sessions (about 2B tokens); weights are promised but not yet posted.
Sources: WorldTUI: I trained a 360M model to pretend to be a terminal (Simon Edwardsson), WorldTUI browser demo, Hacker News discussion, Qwen2.5-Coder-0.5B model card, Ross et al., DAgger (arXiv:1011.0686), Google DeepMind Genie