aryx/IX

A complete computer system in small, readable OCaml programs: a kernel, a shell, C and ML compilers, an editor, a windowing system and more.

OCaml

11

586 commits

updated Oct 12, 2026

See the code

README

IX

A whole computer system in small, readable OCaml programs: an ARM emulator, a kernel, a shell, C and ML compilers, an assembler and a linker, an editor, a build system, a database, version control, and more.

Website: aryx.github.io/IX, with a code map of the whole repository to explore in the browser (below).

IX is a way to learn how a computer system works, end to end, by reading its code. Each part of the system is a separate program, and each program is small enough to read in a few sittings. None of them is a toy, though. The emulator runs real ARM binaries, the compiler makes them, and the kernel boots a real operating system's user programs, up to its windowing system and the network.

The system IX follows is Plan 9, the successor of Unix written at Bell Labs by Unix's own authors. Plan 9 is small, clean, and complete: it has its own kernel, compilers, shell (rc), build tool (mk), editor and windowing system (rio). It is explained program by program in Principia Softwarica, a series of books I (Yoann Padioleau) wrote, and my xix project ports those programs to OCaml at full size. You don't need to know either to read IX. IX takes the same programs and makes each of them as small as it can.

The goal: code a person can understand

Teaching people is the main goal of IX, and the test it sets itself is that one person can understand all of it, not only each program.

Most software fails that test. A kernel, a compiler or a browser of today is millions of lines and grows every year, until no single person understands it, its own authors included. Plan 9 is one of the few exceptions, which is why IX follows it.

Most of IX's code is written by an AI (see Who wrote it), but it does not start from nothing. It starts from designs made by people (Plan 9's, xv6's, xix's), and it is directed to write the smallest and most readable code that does the job. That code is then meant to become literate programs, as in Principia Softwarica: books of a reasonable size that explain all of the code to a human reader.

That is the paradox of IX. The trend these days is to use AI to write more and more code, faster than anyone can read it, until only the AI can add a feature to the program. This was already partly true before AI: many programs had grown so big that they were very hard to change. IX uses AI the other way. Here it rewrites giant programs in far less code, until a whole system is small enough for a person to understand again, and to extend: by hand, or by asking the AI, but in a way that person can still follow. AI can help people take back control of the programs they use.

AI makes the programs smaller. Humans understand more.

Two sizes of each program: m-IX and t-IX

Each program in IX comes in two versions:

  • mini (mini-mk, mini-rc, mini-cc, ...): a faithful reimplementation of the Plan 9 program, only smaller. It is named after the original and does the same thing: its output is the original's, byte for byte. The executables mini-cc and mini-ld make are the ones Plan 9's compiler and linker make. Together, the mini programs are m-IX (a nod to Knuth's MIX computer).
  • tiny (tiny-build, tiny-shell, tiny-c, ...): a free variant, in a single file under tiny/. It is named after what it does, not after the original. It keeps the idea of the original and redesigns the rest, now that compatibility no longer matters. Together, the tiny programs are t-IX.

For example, mini-mk reads real Plan 9 mkfiles and builds all of xix from them, and all of Principia Softwarica's Plan 9, kernel included. tiny-build is a build system in one file of about 450 lines. It keeps mk's rules and % patterns, and uses content digests instead of timestamps. Reading the two side by side shows what is essential to a build system and what is history.

The code map

IX's code map shows the whole repository as a map, in the browser: each folder a region, each file a block the size of its code, each block the code itself once you zoom in. Every folder and file carries a one-line summary, and the X-ray (x) shows each part's skeleton, the few definitions the rest hangs on and how they connect. / searches, a click on a name shows its definition, g shows the dependencies between the parts as a matrix, and h lists every key.

IX's code map: every folder a region, every file a block

A link can open it on any part of the code: a folder, a file, a definition; the tables below link each program so. It is tinybox's code map, from ocaml-elm-playground, after the author's codemap; what it says of each part comes from the .codemapconfig files in each directory.

m-IX: the mini programs

The line counts are OCaml, comments and .mli files included, tests excluded. Each program's map link opens it in the code map.

programwhat it islinesPlan 9 originalcode
mini-5ian ARM emulator for user programs, arm32 and arm64, with Linux's or Plan 9's system calls4,3005imachine/ (map)
mini-qemua Raspberry Pi 1 and Pi 4 (MMU, interrupts, timer, UART, SD card, framebuffer, USB keyboard, mouse and network), which boots xv6, Plan 9 and IX's own kernels, as QEMU does3,500QEMU's raspi machinesraspberry/ (map)
mini-9piPlan 9's kernel in OCaml, on the Pi 1 and the Pi 4: boots Plan 9's own user programs up to the shell, the rio windowing system and TCP9,0009pikernels/9pi/ (map)
mini-xv6MIT's teaching kernel xv6 in OCaml, on the Pi 1 and the Pi 41,600xv6kernels/xv6/ (map)
mini-ccthe C compiler for arm and arm64; the same instructions as Plan 9's 5c and 7c4,6005c, 7clanguages/c/ (map)
mini-mla native compiler for OCaml (the subset IX is written in), for arm and arm64; it compiles all of IX, the kernels included4,300ocaml-light's ocamloptlanguages/ml/ (map)
mini-asmthe assembler for arm and arm648005a, 7aassembler/ (map)
mini-ldthe linker, to Plan 9's a.out, Linux's ELF and macOS's Mach-O (arm64); the same executables as the original's, byte for byte2,6005l, 7llinker/ (map)
mini-rcthe shell2,100rcshell/ (map)
mini-edthe line editor1,200ededitors/ed/ (map)
mini-mkthe build system; builds all of xix and of Principia Softwarica's Plan 9 from their mkfiles2,400mkbuilder/ (map)
mini-chidba relational database: SQL, a query optimizer, B-trees2,900chidb, SQLite's teaching twindatabase/ (map)
mini-git, mini-diff, mini-merge3version control, compatible with git repositories4,700git9, diffversion_control/ (map)

That is about 46,000 lines of OCaml, with mini-lex and mini-yacc (1,200) and what the two kernels share. Under them: 4,600 lines of C and assembly (mini-ml's runtime, the kernels' start), and the libraries, lib_core/ (map) (what the programs share, mini-ml's standard library and the C library under it: 16,200), lib_crypto/ (map) (SHA-1) and lib_compression/ (map) (zlib). m-IX is about 67,000 lines in all (make loc; its log is docs/loc.md).

t-IX: the tiny programs

Each one is a single file in tiny/ (map). tiny/README.md says what idea each one keeps from its original and what it redesigns.

programwhat it islinesmini twinfile
tiny-arman arm64 CPU for user programs: it runs what tiny-assembler, tiny-c and tiny-ml make, as Linux would460mini-5iTinyCPUArm.ml, TinyLibArm.ml (map)
tiny-pitiny-arm's CPU in a Pi 4: exception levels, exceptions, timer, interrupt controller, UART; its page of kernel also runs under QEMU370mini-qemuTinyMachinePi.ml (map)
tiny-cpua CPU of our own design, for teaching, with its assembler560mini-5i, Knuth's MIXTinyCPU.ml, TinyLibCPU.ml (map)
tiny-machinetiny-cpu with what a kernel needs: two modes, traps, a timer, protection, a console, a disk420mini-qemuTinyMachine.ml (map)
tiny-kernela kernel in ML for tiny-machine: fork and exec, preemption, pipes, files570mini-9piTinyKernel.ml (map)
tiny-ca C subset compiler, to arm64 and to tiny-cpu1,200mini-ccTinyC.ml (map)
tiny-mlan ML compiler (Hindley-Milner types, closures, exceptions, a garbage collector) to arm64 and to tiny-cpu1,750mini-mlTinyML.ml (map)
tiny-assemblerassembler and linker in one, to arm64 executables (or a kernel's raw image)710mini-asm, mini-ldTinyAssembler.ml (map)
tiny-shella shell in rc's spirit: lists as the only value680mini-rcTinyShell.ml (map)
tiny-editoran editor with sam's command language800mini-edTinyEditor.ml (map)
tiny-builda build system: rules, %, digests, -j440mini-mkTinyBuildSystem.ml (map)
tiny-dba database whose query language is the relational algebra, over a copy-on-write B-tree620mini-chidbTinyDatabase.ml (map)
tiny-vcsversion control with git's objects, an undo log, and no staging area690mini-gitTinyVCS.ml (map)

That is about 9,000 lines of OCaml; with the operating system below, t-IX is about 16,000 lines in all. tiny-cpu and tiny-machine also run tiny/tiny-os/ (map), an operating system written for them in their assembly and in C for tiny-c: a page-long kernel (v0), an xv6-like kernel with a disk and a shell (v6), and a free variant of it (t6).

Build and run

make          # builds everything; the executables are then in bin/
make test
./bin/mini-mk -h            # every program has -h, with examples
./mini-pi mini-9pi          # boot mini-9pi on mini-qemu, with ix's own programs (mini-rc...)
./mini-pi mini-9pi-principia -g   # with principia's programs and SD card: type rio
./tiny-machine v6           # boot tiny-os's xv6-like kernel on tiny-machine

mini-9pi under mini-qemu, running Plan 9's own rio (kernels/9pi/tests/screenshot.py made the picture):

mini-9pi under mini-qemu: a rio window, with echo, date, ls and ps typed in it

The tests, short and whole:

make test-lite      # under a minute, on all the cores: unit tests, mini-ml on IX,
                    # IX built by IX from nothing, a kernel booted
make test-all       # every test suite, one after the other, with a summary: half an
                    # hour (tests/all.sh -l lists them; -quick: the short ones)

dune install installs both the mini and the tiny executables. make build-docker builds and tests IX in a fresh Ubuntu (the Dockerfile, which GitHub Actions runs with OCaml 4.14.2 and 5.1.1).

The plans, tutorials, manuals and related-work notes are indexed in docs/README.md, and docs/projects.md maps the projects inside IX: the machines (real ARM, or our own) and what runs on each.

Bootstrapping

IX builds itself. The first build needs a compiler from outside: make uses dune, OCaml 4.14 and, under OCaml, gcc. After it, IX's own tools are enough: mini-mk runs the mkfiles, mini-ml, mini-lex and mini-yacc compile the OCaml, mini-cc and mini-asm the C library and mini-ml's runtime, mini-ar and mini-ld link. No OCaml compiler, gcc, GNU binutils or glibc is run or linked; the results are under _mk/.

make                # stage 0: IX built by OCaml and dune (bin/)
make ix             # stage 1: IX built by stage 0's tools, for arm64 (make ix-arm: for arm)
make test-fixpoint  # stage 2: IX built by stage 1's tools: the same files
make kernels-ix     # mini-xv6 and mini-9pi for the Pi 4, the same way
make test-ix        # each program of stage 1 against dune's build of it

Stage 2 is the fixed point: IX built by the programs that IX built gives the same 383 files as stage 1, byte for byte, in about a minute on a large machine. On arm, where the programs run under qemu-arm, the second and third builds are the same 358 files (make test-fixpoint-arm). The kernels built this way boot on the Pi 4 under mini-qemu and QEMU and pass the same checks as the ones built by ocaml-light and gcc (make test-kernels-ix).

What is not built by IX: mini-qemu, which opens its window with SDL, and the tests. The plan and its history are in docs/plans/plan_mkfiles.md and docs/plans/plan_ml_bootstrap.md.

Tiny (and mini), not Toy

There is a good tradition of teaching computer systems by their code: Nand2Tetris (The Elements of Computing Systems) for the whole stack, Minix (Operating Systems: Design and Implementation) for an operating system, and xv6 for a kernel. The Nand2Tetris route makes everything minimal: a made-up machine, a made-up assembler, a made-up OS. IX aims for the full stack too, but makes the programs tiny, not the things they deal with:

  • The machine is real ARM, arm32 and arm64. mini-5i runs user programs; mini-qemu is a whole Raspberry Pi, so that real kernels, not just user programs, run on it. The emulator stops with "unimplemented instruction" on what it does not know, so it also checks that a binary stays inside what IX handles.
  • The binaries are real. mini-cc, mini-asm and mini-ld make them as Plan 9's compilers do, in three formats: ELF for Linux (arm and arm64), Mach-O for macOS (arm64, to sign with codesign), and Plan 9's a.out. So you can use the toolchain for programs on your own machine, as with goken. The same binary runs on IX's emulator, on QEMU and on a real ARM machine. Running it on several and comparing the results is the main test.
  • The system calls are real. User programs talk to the kernel with Plan 9's system call ABI, and mini-9pi runs Plan 9's own user programs, unmodified, from Plan 9's own SD card image.

One group of tiny programs takes the other road on purpose. tiny-cpu and tiny-machine are a made-up machine, as Knuth's MIX and MMIX (MMIXware: A RISC Computer for the Third Millennium) and Nand2Tetris's Hack are, because what they teach is the design of an instruction set: the choices a real one made for history's reasons, made again with hindsight. They stand next to tiny-arm and tiny-pi, the same two programs for real ARM, so that the two roads can be compared.

Still to come

The rest of the system, following the Principia Softwarica books (the names are not final):

partminitinyPlan 9 original
Debuggersmini-db, mini-acidtiny-debuggerdb, acid
Profilersmini-proftiny-profilerprof, tprof
Graphics stackmini-drawtiny-drawlibdraw, libmemdraw, devdraw
Windowing systemmini-riotiny-windowsrio
GUI toolkitmini-paneltiny-guilibpanel
Network stackmini-iptiny-netdevip, libip, lib9p
Web browsermini-mothratiny-browsermothra, webfs
Command-line utilitiesmini-cat, mini-ls, mini-grep, mini-hoc, mini-awk, mini-dc, mini-bc, ...cat, ls, grep, sed, awk, hoc, dc, bc
Gamesthe author's playground's, on its library (games/, lib_playground/): Tetrisgames/4s

mini-9pi already has parts of some of these in its kernel (the draw device, the IP stack), with Plan 9's C programs running on top.

Design

  • Everything is OCaml, the kernel included, and it runs as a real binary. Unlike Nachos, where the "OS" is ordinary code running on the host, mini-9pi is an actual ARM binary: a thin layer of C and assembly boots the machine and starts a stripped-down OCaml runtime, and the kernel is OCaml from there on. The same binary boots on mini-qemu and on QEMU, and is meant for a real Raspberry Pi too. Processes, address spaces, context switches, supervisor and user mode and the system call boundary are therefore real. Today mini-9pi is compiled by ocaml-light's ocamlopt; mini-ml is being written to take over.

     user program (a.out)                          user mode
     ----------------- SWI / trap / irq -----------------------
     mini-9pi (OCaml + thin C/asm runtime shim)     supervisor mode
     ---------------------------------------------------------------
     ARM CPU + CP15 (MMU, modes): a real Raspberry Pi, or
     mini-qemu emulating one, with disk, timer, framebuffer,
     keyboard, mouse and network
    
  • Most tools are terminal programs. They read and write files, stdin and stdout, and depend on nothing graphical. They follow xix's capability style (Cap.*) for OS access.

  • Only mini-qemu depends on a GUI library (SDL), to show the machine's framebuffer and feed it the keyboard and mouse. The machine itself is a pure library, so it also runs in a terminal. The graphical programs (rio and those it runs) run inside the machine and draw into its framebuffer, as on a real computer.

Who wrote it

IX is mostly written by Claude (Anthropic's AI, in Claude Code), under my direction: I choose the design and review the code, and Claude writes most of the lines, for people to read (the goal). xix, on the other hand, I mostly wrote myself. Putting each mini program next to its xix twin makes a fair comparison of the two ways of working. The project started on 2026-09-21; docs/history.md tells how.

docs/yoann_notes/prompt-history.md shows the other side of that work: every prompt I wrote to Claude to build IX, in order and verbatim (typos included), each followed by a short summary of Claude's answer. Hooks in .claude/ append the entries as I work, so the file grows with the repository. Read next to git log, it shows what directing an AI to write a codebase looks like day to day.

The name

IX is 9 in roman numerals (Plan 9), and ix is xix with a letter removed: a smaller xix, as 9 is smaller than 19. It is also the "-ix" of Unix, Minix and Linux with nothing in front. And it has two letters, like rc, mk, ed and the other Unix and Plan 9 names, and like "ai", which writes most of it. In text it is written IX, as UNIX was, and ix where it is a name in the code (ix_core, ix_db).

License

LGPL 2.1 with the OCaml-style linking exception, like xix: see license.txt and copyright.txt.

aryx/IX

A complete computer system in small, readable OCaml programs: a kernel, a shell, C and ML compilers, an editor, a windowing system and more.

OCaml

11

586 commits

updated Oct 12, 2026

See the code

README

IX

A whole computer system in small, readable OCaml programs: an ARM emulator, a kernel, a shell, C and ML compilers, an assembler and a linker, an editor, a build system, a database, version control, and more.

Website: aryx.github.io/IX, with a code map of the whole repository to explore in the browser (below).

IX is a way to learn how a computer system works, end to end, by reading its code. Each part of the system is a separate program, and each program is small enough to read in a few sittings. None of them is a toy, though. The emulator runs real ARM binaries, the compiler makes them, and the kernel boots a real operating system's user programs, up to its windowing system and the network.

The system IX follows is Plan 9, the successor of Unix written at Bell Labs by Unix's own authors. Plan 9 is small, clean, and complete: it has its own kernel, compilers, shell (rc), build tool (mk), editor and windowing system (rio). It is explained program by program in Principia Softwarica, a series of books I (Yoann Padioleau) wrote, and my xix project ports those programs to OCaml at full size. You don't need to know either to read IX. IX takes the same programs and makes each of them as small as it can.

The goal: code a person can understand

Teaching people is the main goal of IX, and the test it sets itself is that one person can understand all of it, not only each program.

Most software fails that test. A kernel, a compiler or a browser of today is millions of lines and grows every year, until no single person understands it, its own authors included. Plan 9 is one of the few exceptions, which is why IX follows it.

Most of IX's code is written by an AI (see Who wrote it), but it does not start from nothing. It starts from designs made by people (Plan 9's, xv6's, xix's), and it is directed to write the smallest and most readable code that does the job. That code is then meant to become literate programs, as in Principia Softwarica: books of a reasonable size that explain all of the code to a human reader.

That is the paradox of IX. The trend these days is to use AI to write more and more code, faster than anyone can read it, until only the AI can add a feature to the program. This was already partly true before AI: many programs had grown so big that they were very hard to change. IX uses AI the other way. Here it rewrites giant programs in far less code, until a whole system is small enough for a person to understand again, and to extend: by hand, or by asking the AI, but in a way that person can still follow. AI can help people take back control of the programs they use.

AI makes the programs smaller. Humans understand more.

Two sizes of each program: m-IX and t-IX

Each program in IX comes in two versions:

  • mini (mini-mk, mini-rc, mini-cc, ...): a faithful reimplementation of the Plan 9 program, only smaller. It is named after the original and does the same thing: its output is the original's, byte for byte. The executables mini-cc and mini-ld make are the ones Plan 9's compiler and linker make. Together, the mini programs are m-IX (a nod to Knuth's MIX computer).
  • tiny (tiny-build, tiny-shell, tiny-c, ...): a free variant, in a single file under tiny/. It is named after what it does, not after the original. It keeps the idea of the original and redesigns the rest, now that compatibility no longer matters. Together, the tiny programs are t-IX.

For example, mini-mk reads real Plan 9 mkfiles and builds all of xix from them, and all of Principia Softwarica's Plan 9, kernel included. tiny-build is a build system in one file of about 450 lines. It keeps mk's rules and % patterns, and uses content digests instead of timestamps. Reading the two side by side shows what is essential to a build system and what is history.

The code map

IX's code map shows the whole repository as a map, in the browser: each folder a region, each file a block the size of its code, each block the code itself once you zoom in. Every folder and file carries a one-line summary, and the X-ray (x) shows each part's skeleton, the few definitions the rest hangs on and how they connect. / searches, a click on a name shows its definition, g shows the dependencies between the parts as a matrix, and h lists every key.

IX's code map: every folder a region, every file a block

A link can open it on any part of the code: a folder, a file, a definition; the tables below link each program so. It is tinybox's code map, from ocaml-elm-playground, after the author's codemap; what it says of each part comes from the .codemapconfig files in each directory.

m-IX: the mini programs

The line counts are OCaml, comments and .mli files included, tests excluded. Each program's map link opens it in the code map.

programwhat it islinesPlan 9 originalcode
mini-5ian ARM emulator for user programs, arm32 and arm64, with Linux's or Plan 9's system calls4,3005imachine/ (map)
mini-qemua Raspberry Pi 1 and Pi 4 (MMU, interrupts, timer, UART, SD card, framebuffer, USB keyboard, mouse and network), which boots xv6, Plan 9 and IX's own kernels, as QEMU does3,500QEMU's raspi machinesraspberry/ (map)
mini-9piPlan 9's kernel in OCaml, on the Pi 1 and the Pi 4: boots Plan 9's own user programs up to the shell, the rio windowing system and TCP9,0009pikernels/9pi/ (map)
mini-xv6MIT's teaching kernel xv6 in OCaml, on the Pi 1 and the Pi 41,600xv6kernels/xv6/ (map)
mini-ccthe C compiler for arm and arm64; the same instructions as Plan 9's 5c and 7c4,6005c, 7clanguages/c/ (map)
mini-mla native compiler for OCaml (the subset IX is written in), for arm and arm64; it compiles all of IX, the kernels included4,300ocaml-light's ocamloptlanguages/ml/ (map)
mini-asmthe assembler for arm and arm648005a, 7aassembler/ (map)
mini-ldthe linker, to Plan 9's a.out, Linux's ELF and macOS's Mach-O (arm64); the same executables as the original's, byte for byte2,6005l, 7llinker/ (map)
mini-rcthe shell2,100rcshell/ (map)
mini-edthe line editor1,200ededitors/ed/ (map)
mini-mkthe build system; builds all of xix and of Principia Softwarica's Plan 9 from their mkfiles2,400mkbuilder/ (map)
mini-chidba relational database: SQL, a query optimizer, B-trees2,900chidb, SQLite's teaching twindatabase/ (map)
mini-git, mini-diff, mini-merge3version control, compatible with git repositories4,700git9, diffversion_control/ (map)

That is about 46,000 lines of OCaml, with mini-lex and mini-yacc (1,200) and what the two kernels share. Under them: 4,600 lines of C and assembly (mini-ml's runtime, the kernels' start), and the libraries, lib_core/ (map) (what the programs share, mini-ml's standard library and the C library under it: 16,200), lib_crypto/ (map) (SHA-1) and lib_compression/ (map) (zlib). m-IX is about 67,000 lines in all (make loc; its log is docs/loc.md).

t-IX: the tiny programs

Each one is a single file in tiny/ (map). tiny/README.md says what idea each one keeps from its original and what it redesigns.

programwhat it islinesmini twinfile
tiny-arman arm64 CPU for user programs: it runs what tiny-assembler, tiny-c and tiny-ml make, as Linux would460mini-5iTinyCPUArm.ml, TinyLibArm.ml (map)
tiny-pitiny-arm's CPU in a Pi 4: exception levels, exceptions, timer, interrupt controller, UART; its page of kernel also runs under QEMU370mini-qemuTinyMachinePi.ml (map)
tiny-cpua CPU of our own design, for teaching, with its assembler560mini-5i, Knuth's MIXTinyCPU.ml, TinyLibCPU.ml (map)
tiny-machinetiny-cpu with what a kernel needs: two modes, traps, a timer, protection, a console, a disk420mini-qemuTinyMachine.ml (map)
tiny-kernela kernel in ML for tiny-machine: fork and exec, preemption, pipes, files570mini-9piTinyKernel.ml (map)
tiny-ca C subset compiler, to arm64 and to tiny-cpu1,200mini-ccTinyC.ml (map)
tiny-mlan ML compiler (Hindley-Milner types, closures, exceptions, a garbage collector) to arm64 and to tiny-cpu1,750mini-mlTinyML.ml (map)
tiny-assemblerassembler and linker in one, to arm64 executables (or a kernel's raw image)710mini-asm, mini-ldTinyAssembler.ml (map)
tiny-shella shell in rc's spirit: lists as the only value680mini-rcTinyShell.ml (map)
tiny-editoran editor with sam's command language800mini-edTinyEditor.ml (map)
tiny-builda build system: rules, %, digests, -j440mini-mkTinyBuildSystem.ml (map)
tiny-dba database whose query language is the relational algebra, over a copy-on-write B-tree620mini-chidbTinyDatabase.ml (map)
tiny-vcsversion control with git's objects, an undo log, and no staging area690mini-gitTinyVCS.ml (map)

That is about 9,000 lines of OCaml; with the operating system below, t-IX is about 16,000 lines in all. tiny-cpu and tiny-machine also run tiny/tiny-os/ (map), an operating system written for them in their assembly and in C for tiny-c: a page-long kernel (v0), an xv6-like kernel with a disk and a shell (v6), and a free variant of it (t6).

Build and run

make          # builds everything; the executables are then in bin/
make test
./bin/mini-mk -h            # every program has -h, with examples
./mini-pi mini-9pi          # boot mini-9pi on mini-qemu, with ix's own programs (mini-rc...)
./mini-pi mini-9pi-principia -g   # with principia's programs and SD card: type rio
./tiny-machine v6           # boot tiny-os's xv6-like kernel on tiny-machine

mini-9pi under mini-qemu, running Plan 9's own rio (kernels/9pi/tests/screenshot.py made the picture):

mini-9pi under mini-qemu: a rio window, with echo, date, ls and ps typed in it

The tests, short and whole:

make test-lite      # under a minute, on all the cores: unit tests, mini-ml on IX,
                    # IX built by IX from nothing, a kernel booted
make test-all       # every test suite, one after the other, with a summary: half an
                    # hour (tests/all.sh -l lists them; -quick: the short ones)

dune install installs both the mini and the tiny executables. make build-docker builds and tests IX in a fresh Ubuntu (the Dockerfile, which GitHub Actions runs with OCaml 4.14.2 and 5.1.1).

The plans, tutorials, manuals and related-work notes are indexed in docs/README.md, and docs/projects.md maps the projects inside IX: the machines (real ARM, or our own) and what runs on each.

Bootstrapping

IX builds itself. The first build needs a compiler from outside: make uses dune, OCaml 4.14 and, under OCaml, gcc. After it, IX's own tools are enough: mini-mk runs the mkfiles, mini-ml, mini-lex and mini-yacc compile the OCaml, mini-cc and mini-asm the C library and mini-ml's runtime, mini-ar and mini-ld link. No OCaml compiler, gcc, GNU binutils or glibc is run or linked; the results are under _mk/.

make                # stage 0: IX built by OCaml and dune (bin/)
make ix             # stage 1: IX built by stage 0's tools, for arm64 (make ix-arm: for arm)
make test-fixpoint  # stage 2: IX built by stage 1's tools: the same files
make kernels-ix     # mini-xv6 and mini-9pi for the Pi 4, the same way
make test-ix        # each program of stage 1 against dune's build of it

Stage 2 is the fixed point: IX built by the programs that IX built gives the same 383 files as stage 1, byte for byte, in about a minute on a large machine. On arm, where the programs run under qemu-arm, the second and third builds are the same 358 files (make test-fixpoint-arm). The kernels built this way boot on the Pi 4 under mini-qemu and QEMU and pass the same checks as the ones built by ocaml-light and gcc (make test-kernels-ix).

What is not built by IX: mini-qemu, which opens its window with SDL, and the tests. The plan and its history are in docs/plans/plan_mkfiles.md and docs/plans/plan_ml_bootstrap.md.

Tiny (and mini), not Toy

There is a good tradition of teaching computer systems by their code: Nand2Tetris (The Elements of Computing Systems) for the whole stack, Minix (Operating Systems: Design and Implementation) for an operating system, and xv6 for a kernel. The Nand2Tetris route makes everything minimal: a made-up machine, a made-up assembler, a made-up OS. IX aims for the full stack too, but makes the programs tiny, not the things they deal with:

  • The machine is real ARM, arm32 and arm64. mini-5i runs user programs; mini-qemu is a whole Raspberry Pi, so that real kernels, not just user programs, run on it. The emulator stops with "unimplemented instruction" on what it does not know, so it also checks that a binary stays inside what IX handles.
  • The binaries are real. mini-cc, mini-asm and mini-ld make them as Plan 9's compilers do, in three formats: ELF for Linux (arm and arm64), Mach-O for macOS (arm64, to sign with codesign), and Plan 9's a.out. So you can use the toolchain for programs on your own machine, as with goken. The same binary runs on IX's emulator, on QEMU and on a real ARM machine. Running it on several and comparing the results is the main test.
  • The system calls are real. User programs talk to the kernel with Plan 9's system call ABI, and mini-9pi runs Plan 9's own user programs, unmodified, from Plan 9's own SD card image.

One group of tiny programs takes the other road on purpose. tiny-cpu and tiny-machine are a made-up machine, as Knuth's MIX and MMIX (MMIXware: A RISC Computer for the Third Millennium) and Nand2Tetris's Hack are, because what they teach is the design of an instruction set: the choices a real one made for history's reasons, made again with hindsight. They stand next to tiny-arm and tiny-pi, the same two programs for real ARM, so that the two roads can be compared.

Still to come

The rest of the system, following the Principia Softwarica books (the names are not final):

partminitinyPlan 9 original
Debuggersmini-db, mini-acidtiny-debuggerdb, acid
Profilersmini-proftiny-profilerprof, tprof
Graphics stackmini-drawtiny-drawlibdraw, libmemdraw, devdraw
Windowing systemmini-riotiny-windowsrio
GUI toolkitmini-paneltiny-guilibpanel
Network stackmini-iptiny-netdevip, libip, lib9p
Web browsermini-mothratiny-browsermothra, webfs
Command-line utilitiesmini-cat, mini-ls, mini-grep, mini-hoc, mini-awk, mini-dc, mini-bc, ...cat, ls, grep, sed, awk, hoc, dc, bc
Gamesthe author's playground's, on its library (games/, lib_playground/): Tetrisgames/4s

mini-9pi already has parts of some of these in its kernel (the draw device, the IP stack), with Plan 9's C programs running on top.

Design

  • Everything is OCaml, the kernel included, and it runs as a real binary. Unlike Nachos, where the "OS" is ordinary code running on the host, mini-9pi is an actual ARM binary: a thin layer of C and assembly boots the machine and starts a stripped-down OCaml runtime, and the kernel is OCaml from there on. The same binary boots on mini-qemu and on QEMU, and is meant for a real Raspberry Pi too. Processes, address spaces, context switches, supervisor and user mode and the system call boundary are therefore real. Today mini-9pi is compiled by ocaml-light's ocamlopt; mini-ml is being written to take over.

     user program (a.out)                          user mode
     ----------------- SWI / trap / irq -----------------------
     mini-9pi (OCaml + thin C/asm runtime shim)     supervisor mode
     ---------------------------------------------------------------
     ARM CPU + CP15 (MMU, modes): a real Raspberry Pi, or
     mini-qemu emulating one, with disk, timer, framebuffer,
     keyboard, mouse and network
    
  • Most tools are terminal programs. They read and write files, stdin and stdout, and depend on nothing graphical. They follow xix's capability style (Cap.*) for OS access.

  • Only mini-qemu depends on a GUI library (SDL), to show the machine's framebuffer and feed it the keyboard and mouse. The machine itself is a pure library, so it also runs in a terminal. The graphical programs (rio and those it runs) run inside the machine and draw into its framebuffer, as on a real computer.

Who wrote it

IX is mostly written by Claude (Anthropic's AI, in Claude Code), under my direction: I choose the design and review the code, and Claude writes most of the lines, for people to read (the goal). xix, on the other hand, I mostly wrote myself. Putting each mini program next to its xix twin makes a fair comparison of the two ways of working. The project started on 2026-09-21; docs/history.md tells how.

docs/yoann_notes/prompt-history.md shows the other side of that work: every prompt I wrote to Claude to build IX, in order and verbatim (typos included), each followed by a short summary of Claude's answer. Hooks in .claude/ append the entries as I work, so the file grows with the repository. Read next to git log, it shows what directing an AI to write a codebase looks like day to day.

The name

IX is 9 in roman numerals (Plan 9), and ix is xix with a letter removed: a smaller xix, as 9 is smaller than 19. It is also the "-ix" of Unix, Minix and Linux with nothing in front. And it has two letters, like rc, mk, ed and the other Unix and Plan 9 names, and like "ai", which writes most of it. In text it is written IX, as UNIX was, and ix where it is a name in the code (ix_core, ix_db).

License

LGPL 2.1 with the OCaml-style linking exception, like xix: see license.txt and copyright.txt.

Significant stargazers

Martin Jambon

324 followers · starred Oct 2026

David Sancho

453 followers · starred Sep 2026

Xavier Van de Woestyne

366 followers · starred Oct 2026

Nathan Guermond

23 followers · starred Oct 2026