I Like Assembly
I like assembly.
It was the first language I "learned." I was twelve, didn't have a computer, so I learned on paper. And apparently it worked — because a year later, when I finally sat down at a machine, my first programs, carefully written on paper, converted to hex with addresses calculated by hand, actually ran when I typed them into a PMD-85. I learned BASIC afterwards. And even though I now write ten levels of abstraction above all that, I never forgot assembly and I still like it.
I wouldn't write anything big in it, of course. I'm not a fanatic or an orthodox "programmer." But I know it, I can do it, and I remember it.
You probably know I've been building an 8-bit online assembler. The first prototype went live sometime around 2014, give or take. It had an editor, a compiler, a debugger, and a handful of emulators for old 8-bit machines. I cobbled it together in spare moments and then maintained it here and there.
Around 2020 I ran out of time for it, and besides, I thought it deserved a rewrite. So I tried rewriting the core in more modern ES6 — at least to get proper modules in there and cover it with tests. It took a while, but it eventually came together and I published it.
Then I thought the IDE itself could use a rewrite. I experimented for a bit, tried integrating Monaco into Svelte, then Svelte changed under my hands and turned into a runic React, so I told myself I'd rewrite it someday — and that "someday" kept receding…
Until this year. There I was, lying in bed, suffering through a gallbladder colic. There's not much you can do in that state. You lie there, grateful to be breathing, and you try to breathe as little as possible so it doesn't hurt more than strictly necessary. After one of those attacks, around half past midnight, I thought I'd take a look at how that celebrated OpenCode with its "coding" models actually performs. I think Minimax M2.5 was just out or something like that, so I had it running. Working was out of the question, but I wanted to try it. My eyes were closing from exhaustion, so I typed something like:
Build the base for a web app — an IDE for an online compiler. Menu, file tree panel, editor panel (Monaco), status bar. You pick the frontend setup. Probably no Bootstrap. No React, no Vue, no Svelte. SPA, ES6, async. Set up a dev server and build system too.
Then I put the laptop down beside the bed and fell asleep.
In the morning I woke up and went to see where it had gotten stuck. To my surprise, it said: "Done, run it with npm run dev." So I ran it. And what do you think?
I didn't believe it had pulled it off. But it had. There was an IDE with a menu, a working Monaco, working web workers, components via Shoelace — and it looked decent.
Up to that point the maximum I'd gotten out of these tools was "help me with this function" or "write me this kind of module." And even then I had to hover over it, because the models had a tendency to reinvent the wheel, skip available libraries, or slap in a heavyweight Axios where a plain fetch would do.
It was a shot in the dark, but it landed. It did the most annoying part of the work for me. If you've ever integrated bare Monaco into anything, you know what I mean. It encouraged me, so I kept going: connect the filesystem, hook up the existing compiler, make the UI actually make sense, keep telling it "not like that" and nudging it in the right direction.
"Stop! Why this way? Do it simply — do it like this!"
"No, I don't want that. I want it to compile the file!"
"Why did you invent this toggle? You have Shoelace for that!"
Like working with an eager junior.
But then it finished, and it was satisfying enough that I decided this was the way forward.
"Add Auth0 login."
"Build a database backend to store the projects."
I just sat there, gave orders, reviewed, and steered. It looks simple from the outside, but there was a lot of other work behind it. "Why are you using this API, it's been deprecated for ages!" Or: "This code is a mess, throw out that middleware and write it yourself. And add JSDoc." Or: "Auth0 doesn't support this method anymore!"
Around that time Claude Code started behaving sensibly on Windows too, so I put it on the main line of development. OpenCode was meanwhile rewriting my BASIC compiler for the 8080 to also support the 6502, and I was using Codex to work on a second version with translation to p-codes.
I gradually improved the workflow — a Ralph Loop here, some skills there — and with that, efficiency grew. I became ambitious, started dreaming up more things to add, had it suggest what else to build, had it research which features would make sense, then planned them and had them developed. It's fun, when you know what you're doing.
A lot of the work was done by subagents. "We have this feature working for one processor. Do it for the others too!" Syntax highlighting for all supported processors, for example. I wouldn't have written that by hand — I really wouldn't. The subagents did, and they seemed happy about it.
Then I had them rewrite the old computer emulators from the original ASM80. They wrestled with it, but they got there. Along the way they came up with small niceties, like showing the cycle count for each instruction right in the editor.
I had it write a manual, modeled on those old 1980s ones. As the assembler develops, a team from paperclip.ai runs in the background, watching commits across all the components and updating and expanding the manual accordingly.
When I was satisfied and didn't know what to add next, I went for a checkup at the hospital, and on the way I was thinking about a slightly mad-sounding idea: what if you could run a piece of code right in the editor and watch — while you're writing — how register values change, what's happening in memory, how many cycles it takes. From the waiting room I worked through it with Claude, figuring out the best way to implement and integrate it, and by the time my name was called, I had a spec written up.
This is a clear example of how detailed preparation pays off, and how useful it is to push the LLM into "ask questions and argue" mode. During the conversation I pulled it back several times when it started "thinking more than was good for it" and had a tendency to overcomplicate things. The most common thing I said was: "That's unnecessary. Just do it like this!"
I handed it the spec that afternoon. By evening it was done. Naturally I sent it back for revisions about ten times, but in the end it iterated and converged toward what I had in mind — even though I hadn't precisely known what I wanted beforehand.
From there it was a short step to the "playbook" — something like a Jupyter Notebook, but for assembly. You have text — instructions or a tutorial — and embedded assembly code you can compile and run in the emulator. You can modify it, see what it does, see how a change ripples through. I think it could be useful for teaching.
But I still felt I needed something more. I have assembly, I have BASIC, I have live terminals and emulators — but it still needs something, something… Something like a C compiler!
It doesn't have to be GNU C. It won't be cc65 or SDCC — the licensing situation is complicated there, and I'd have to run them server-side, which would be slow, plus all the security concerns and connectors for ASM80. So I took a nice C compiler written in C and had it rewritten in ES6 to run in the browser. Not WASM — an actual rewrite. Plus a small test suite covering all supported constructs. Two days, and it worked.
Then came stripping out the 16-bit x86 foundations, building a codegen for Z80, 6502, and 6809 (phase 1), preparing another round of tests, then E2E tests — which required turning some parts of ASM80 (compiler, linker, archiver, emulator) into CLI utilities. The compiler compiles; I just don't like the output. It's not optimized — a clean compiler translates C constructs pretty mechanically. Sometimes it loads variables into registers it already has them in, sometimes it computes a[0] and adds a pointer to A with zero, sometimes it generates dead code that the processor will never reach. So since yesterday I've been working on code optimizations. All the features are implemented and covered by tests, so it's time to work on the code generator.
As I write this, in the second window I'm watching it wrestle with the problem. I show it a construction that makes no sense, it analyzes why it makes no sense, figures out how it arises, digs around inside the compiler to find how to avoid it, writes a spec, writes a plan, a colleague reviews that plan, they go back and forth three times, then it opens a worktree, launches subagents to execute the plan, test it, commit it — and I expect it to be done in about an hour.
It has a moment to itself right now, so I'm thinking about what I can do while the robot is working…
Oh well. I'm looking forward to writing libc. That'll finally be proper hard work. I'm not handing that one over to it. Well — maybe the boring parts.
I'll finish writing and go think of something to keep it busy overnight. :)




