https://github.com/unix-v4-commentary/unix-v4-source-commentary
A comprehensive, line-by-line commentary on the UNIX Fourth Edition source code (released November 1973; tape recovered from June 1974 distribution).
./bin/mu -B -o ... -p muos/amd64 ... target.
@prologic@twtxt.net Iād love to take a look at the code. š
Iām kind of curious to know how much Assembly I need vs. How much of a microkernel can I build purely in Mu (µ)? š¤
Canāt really answer that, because I only made a working kernel for 16-bit real mode yet. That is 99% C, though, only syscall entry points are Assembly. (The OpenWatcom compiler provides C wrappers for triggering software interrupts, which makes things easier.)
But in long mode? No idea yet. š At least changing the page tables will require a tiny little bit of Assembly.
Took me nearly all week (in my spare time), but Mu (µ) finally officially support linux/amd64 š„³ I completely refactored the native code backend and borrowed a lot of the structure from another project called wazero (the zero dependency Go WASM runtime/compiler). This is amazing stuff because now Mu (µ) runs in more places natively, as well as running everywhere Go runs via the bytecode VM interpreter š¤
Iām trying to implement configurable key bindings in tt. Boy, is parsing the key names into tcell.EventKeys a horrible thing. This type consists of three information:
- maybe a predefined compound key sequence, like Ctrl+A
- maybe some modifiers, such as Shift, Ctrl, etc.
- maybe a rune if neither modifiers are present nor a predefined compound key exists
Itās hardcoded usage results in code like this:
func (t *TreeView[T]) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
switch event.Key() {
case tcell.KeyUp:
t.moveUp()
case tcell.KeyDown:
t.moveDown()
case tcell.KeyHome:
t.moveTop()
case tcell.KeyEnd:
t.moveBottom()
case tcell.KeyCtrlE:
t.moveScrollOffsetDown()
case tcell.KeyCtrlY:
t.moveScrollOffsetUp()
case tcell.KeyTab, tcell.KeyBacktab:
if t.finished != nil {
t.finished(event.Key())
}
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'k':
t.moveUp()
case 'j':
t.moveDown()
case 'g':
t.moveTop()
case 'G':
t.moveBottom()
}
}
}
})
}
This data structure is just awful to handle and especially initialize in my opinion. Some compound tcell.Keys are mapped to human-readable names in tcell.KeyNames. However, these names always use - to join modifiers, e.g. resulting in Ctrl-A, whereas tcell.EventKey.Name() produces +-delimited strings, e.g. Ctrl+A. Gnaarf, why this asymmetry!? O_o
I just checked k9s and theyāre extending tcell.KeyNames with their own tcell.Key definitions like crazy: https://github.com/derailed/k9s/blob/master/internal/ui/key.go Then, they convert an original tcell.EventKey to tcell.Key: https://github.com/derailed/k9s/blob/b53f3091ca2d9ab963913b0d5e59376aea3f3e51/internal/ui/app.go#L287 This must be used when actually handling keyboard input: https://github.com/derailed/k9s/blob/e55083ba271eed6fc4014674890f70c5ed6c70e0/internal/ui/tree.go#L101
This seems to be much nicer to use. However, I fear this will break eventually. And itās more fragile in general, because itās rather easy to forget the conversion or one can get confused whether a certain key at hand is now an original tcell.Key coming from the library or an āextendedā one.
I will see if I can find some other programs that provide configurable tcell key bindings.
Since I used so much Rust during the holidays, I got totally used to rustfmt. I now use similar tools for Python (black and isort).
What have I been doing all these years?! I never want to format code manually again. š¤£š
Vacation: Doing crazy things like C on DOS, lots of Rust, bare-metal assembly code, everything is fine.
Back at work: How the fuck do I move an email in this web mail program? Am I stupid? š®āšØ
I came across this on āWhy Is SQLite Coded In Cā, which I found interesting:
āThere has lately been a lot of interest in āsafeā programming languages like Rust or Go in which it is impossible, or is at least difficult, to make common programming errors like memory leaks or array overruns.ā
If thatās true, then encountering those issues means the programmer is, simply, horrible?
Spent most of the long weekend working on a few coding projects⦠specifically, I pushed some updates for TwtKpr to my test instance before spending some time working on the build process and demo page for my new twtxt-parsing library⦠which lead me to make some changes to my existing fluent-dom-esm library.
So, nothing actually got finished, but the incremental updates continueā¦
fib(35) doesn't regress too badly as I continue to evolve the language.
@lyse@lyse.isobeef.org Itās actually not nearly as half bad as I really thought it would be. Just having to eventually deal with the ālowering downā to machine code / ARM64 assembly in the end once youāve verified the semantics in the VM.
println("Hello World"):
@lyse@lyse.isobeef.org A āHello Worldā binary is ~372KB in size. I currently have peephole optimization and deac code optimizations in play, and a few other performance related ones, but nothing too fancy. I have a test case that ensures fib(35) doesnāt regress too badly as I continue to evolve the language.
Opinion / Question timeā¦
Do you think Mu (µ)ās native compiler and therefore emitted machine code āruntimeā (which obviously adds a bit of weight to the resulting binary, and runtime overheads) needs to support āruntime stack tracesā, or would it be enough to only support that in the bytecode VM interpreter for debuggability / quick feedback loops and instead just rely on flat (no stacktraces) errors in natively built compiled executables?
So in effect:
Stack Traces:
- Bytecode VM Interpreter: ā
- Native Code Executables: ā
Nice! š Here are the startup latencies for the simplest Mu (µ) program. println("Hello World"):
- Interpreter: ~5ms
- Native Code: ~1.5ms
@shinyoukai@neko.laidback.moe We finally abandoned our GitLab. I publicly mirrored my code in the Mills Data Center a few days ago: https://git.mills.io/lyse/tt2
@movq@www.uninformativ.de Well, just a very limited subset thereof:
- inline and multiline code blocks using single/double/triple backticks (but no code blocks with just indentation)
- markdown links using using
[text](url)
- markdown media links using

And thatās it. No bold, italics, lists, quotes, headlines, etc.
Just like mentions, plain URLs, markdown links and markdown media URLs are highlighted and available in the URLs View. Theyāre also colored differently, similarly to code segments.
I definitely should write some documentation and provide screenshots.
Hurray, I finally fixed another rendering bug in tt that was bugging me for a long time. Previously, when there were empty lines in a markdown multiline code block, the background color of the code block had not been used for the empty lines. So, this then looked as if there were actually several code blocks instead of a single one.
https://lyse.isobeef.org/tmp/tt-bugfix-empty-lines-in-multiline-code-blocks.png
mu (µ) now has builtin code formatting and linting tools, making µ far more useful and useable as a general purpose programming language. Mu now includes:
- An interpreter for quick āscriptinogā
- A native code compiler for building native executables (Darwin / macOS only for now)
- A builtin set of developer tools, currently: fmt (-fmt), check (-check) and test (-test).
I just fixed another bug in tt where the language hint in multiline markdown code blocks had not been stripped before rendering. It just looked like it was part of the actual code, which was ugly. I now throw it away. Actually, itās already extracted into the data model for possible future syntax highlighting.
os.UserConfigDir() up until a few seconds ago! I always implemented that myself.
@shinyoukai@neko.laidback.moe Yeah, they donāt truly support XDG. In fact, I looked in the Go stdlib source code to notice all the differences and shortcomings.
$HOME is not specified it tries to resolve the user's home directory by user.Current().HomeDir. Maybe that's overkill, I have to check the XDG spec.
Ok, the standard library implementation is wonky at best, at least in regards to XDG, because it really doesnāt implement it properly. https://github.com/golang/go/issues/62382 I stick to my own code then. It doesnāt properly support anything else than Linux or Unixes that use XDG, but personally, I donāt care about them anyway. And the cross-platform situation is a giant mess. Unsurprisingly.
@movq@www.uninformativ.de Thanks! Iāll have a look at SnipMate. Currently, Iām (mis)using the abbreviation mechanism to expand a code snippet inplace, e.g.
autocmd FileType go inoreab <buffer> testfunc func Test(t *testing.T) {<CR>}<ESC>k0wwi
or this monstrosity:
autocmd FileType go inoreab <buffer> tabletest for _, tt := range []struct {<CR> name string<CR><CR><BS>}{<CR> {<CR> name: "",<CR><BS>},<CR><BS>} {<CR> t.Run(tt.name, func(t *testing.T) {<CR><CR>})<CR><BS>}<ESC>9ki<TAB>
But this of course has the disadvantage that I still have to remove the last space or tab to trigger the expansion by hand again. Itās a bit annoying, but better than typing it out by hand.
@lyse@lyse.isobeef.org I can tell you this right now, writing assembly / machine code is fucking hard work⢠š Iām sure @movq@www.uninformativ.de can affirm 𤣠And when it all goes to shit⢠(which it does often), man is debugging fucking hard as hell! Without debug symbols I canāt use the regular tools like lldb or gdb š
@prologic@twtxt.net Yeah, the parser part is what I typically enjoy. Havenāt really looked into code generation itself.
Iām currently looking at your µ commits from the last few days. Holy cow! :-)
Whoo! I fixed one of the hardest bugs in mu (µ) I think Iāve had to figure out. Took me several days in fact to figure it out. The basic problem was, println(1, 2) was bring printed as 1 2 in the bytecode VM and 1 nil when natively compiled to machine code on macOS. In the end it turned out the machine code being generated / emitted meant that the list pointers for the rest... of the variadic arguments was being slot into a register that was being clobbered by the mu_retain and mu_release calls and effectively getting freed up on first use by the RC (reference counting) garbage collector š¤¦āāļø
@shinyoukai@neko.laidback.moe Nah itās more like thereās a lot of repeated code, because when you go from source language to intermediate representation to machine code, well you just end up writing a lot of the same patterns over and over again. I need to dedupe this I think.
The compiler technique Iām using here is to not āemitā most of the runtime if itās actually never used in your program, and also dropping dead code in the SSA pass.
Hmmm I need to figure out a way to reduce the no. of lines of code / complexity of the ARM64 native code emitter for mu (µ). Itās insane really, itās a whopping ~6k SLOC, the next biggest source file is the compiler at only ~800 SLOC š¤
@movq@www.uninformativ.de I think I can get binaries even smaller with a bit more work and effort š¤ But yeah still working on the native code generation (at least for macOS targets)
@movq@www.uninformativ.de Oh thatās fine, Mu can compile to native code and so far binaries. at least on macOS are in the order of Kb in size š
My little toy operating system from last year runs in 16-bit Real Mode (like DOS). Since Iāve recently figured out how to switch to 64-bit Long Mode right after BIOS boot, I now have a little program that performs this switch on my toy OS. It will load and run any x86-64 program, assuming itās freestanding, a flat binary, and small enough (< 128 KiB code, only uses the first 2 MiB of memory).
Here Iām running a little C program (compiled using normal GCC, no Watcom trickery):
https://movq.de/v/b27ced6dcb/los86%2D64.mp4
https://movq.de/v/b27ced6dcb/c.png
Next steps could include:
- Use Rust instead of C for that 64-bit program?
- Provide interrupt service routines. (At the moment, it just keeps interrupts disabled.)
@prologic@twtxt.net You write so much code ⦠itās incredible. š
@movq@www.uninformativ.de @kiwu@twtxt.net it just so happens to be a happy coincidence that Iām extending muās capabilities to now include a native toolchain-free compiler (doesnāt rely on any external gcc/clang or linkers, etc) that lowers the mu source code into an intermediate representation / IR (what @movq@www.uninformativ.de refers to as āthick layers of abstractionsāā¦) and finally to SSA + ARM64 + Mach-O encoder to produce native binary executables (at least for me on my Mac, Linux may some later?) š¤£
Got a nice conspiracy theory for you:
https://mastodon.social/@mcc/115670290552252848
Actually wait I just thought about this and realized that the precise timing of the ACTUAL GitHub seed bank, by which I mean the Arctic Code Vault, on 2020-02-02, makes it more or less a perfect snapshot of pre-Copilot GitHub. Also precisely timed before we all got brain damage from COVID. This is the only remaining archive of source code by people with a fully working sense of smell
(Bonus points because the Arctic World Archive is located in Svaldbard and thatās the name of the AI in Stacey Kadeās āCold Eternityā.)
I cleaned up all my of AoC (Advent of Code) 2025 solutions, refactored many of the utilities I had to write as reusable libraries, re-tested Day 1 (but nothing else). here it is if youāre curious! This is written in mu, my own language I built as a self-hosted minimal compiler/vm with very few types and builtins.
I finished all 12 days of Advent of Code 2025! #AdventOfCode https://adventofcode.com ā did it in my own language, mu (Go/Python-ish, dynamic, int/bool/string, no floats/bitwise). Found a VM bug, fixed it, and the self-hosted mu compiler/VM (written in mu, host in Go) carried me through. š„³
I just completed āPrinting Departmentā - Day 4 - Advent of Code 2025 #AdventOfCode https://adventofcode.com/2025/day/4 ā Again, Iām doing this in mu, a Go(ish) / Python(ish) dynamic langugage that I had to design and build first which has very few builtins and only a handful of types (ints, no flots). š¤£
I just completed āLobbyā - Day 3 - Advent of Code 2025 #AdventOfCode https://adventofcode.com/2025/day/3 ā Again, Iām doing this in mu, a Go(ish) / Python(ish) dynamic langugage that I had to design and build first which has very few builtins and only a handful of types (ints, no flots). š¤£
I just completed āGift Shopā - Day 2 - Advent of Code 2025 #AdventOfCode https://adventofcode.com/2025/day/2 ā But again, Iām solving this in my own language mu that I had to build first š¤£
I just completed āSecret Entranceā - Day 1 - Advent of Code 2025 #AdventOfCode https://adventofcode.com/2025/day/1 ā However I did it in my own toy programming language called mu, which I had to build first š¤£
Alright, Advent of Code is over:
https://www.uninformativ.de/blog/postings/2025-12-12/0/POSTING-en.html
Itās been quite the time sink, especially with the DOS games on top, but it was fun. š„³
In case youāre wondering: All puzzles (except for part 2 of day 10) were doable in Python 1 on SuSE Linux 6.4 and ran in a finite time on the Pentium 133. Puzzle 10/2 might have been doable as well if I had better education. š¤£
my MIND is a MACHINE that turns ILLEGIBLE CODE into ILLEGIBLE CODE

iāve learned a lot of lessons from writing my notes app, gonna apply this to bbycll and refactor the code to make it way more legible cause my custom templating system is only kind of a giant mess
@prologic@twtxt.net Here you go:
(LTT = āLinus Tech Tipsā, thatās the host.)
LTT: There was a recent thing from a major tech company, where developers were asked to say how many lines of code they wrote ā and if it wasnāt enough, they were terminated. And there was someone here that was extremely upset about that approach to measuring productivity, becauseā
Torvalds: Oh yeah, no, you shouldnāt even be upset. At that point, thatās just incompetence. Anybody who thinks thatās a valid metric is too stupid to work at a tech company.
LTT: You do know who you just said that about, right?
Torvalds: No.
LTT: Oh. Uh, he was a prominent figure in the, uh, improved efficiency of the US government recently.
Torvalds: Oh. Apparently I was spot on.
@lyse@lyse.isobeef.org My theory is that these people simply donāt do ācode archeologyā. When something breaks, they donāt reach for git log. They simply donāt experience the pain that comes with bad commits / commit messages.
Or is that different in your company? š
@movq@www.uninformativ.de Same. :ā-( I just donāt get how people do code archeology with all their shit messages and huge commits changing a gazillion of different things. I always try to lead by setting good examples, but nofuckingbody is picking up on that. At all. Even when bringing this up every now and then.
@itsericwoodward@itsericwoodward.com Nice to see someone else also participating! š„³
(Btw, they donāt want us to share our inputs: https://www.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs/ Yeah, itās a bit annoying. I also have to do quite a bit of filtering on my repo ā¦)
Most of the Advent of Code action happens on the Fediverse, Iām afraid:
https://tilde.zone/@movq/115595022987289988
Thereās just way more people over there who participate. š„“
Working on day 3 of the Advent of Code 2025: https://adventofcode.com/
My solutions repo: https://git.itsericwoodward.com/eric/aoc-2025
@prologic@twtxt.net Using your own language?! Thatās really nice! I hope you get home soon so you can give the code a try. š
I actually canāt progress to day two till I get home 𤣠ā I havenāt pushed the code for the mu compiler yet š¤¦āāļø So no-one can check my work even if they were so kind š¤£
completely untested as i have no remote way of running mu code from Vietnam š¤£