stage0 is the bottom of the bootstrapping chain, and it is meant to be read
A set of minimal dependency bootstrap binaries
At a glance
- What is it?
- stage0 is a set of minimal hex programs by Jeremiah Orians that bootstrap a path to a C compiler able to compile GCC, with the explicit constraint that each binary is 1 KByte or less and the code is understandable by most programmers. It fits someone building a self-hosting toolchain, and it does not fit anyone who just wants a compiler.
- Who is it for?
- stage0 fits a person deliberately building a self-hosting toolchain from the bottom up, or a teaching project that wants to show what a compiler bootstrap actually consists of. It does not fit a team that needs a compiler, and it is not a build system anyone can adopt.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 128 days ago.
- What is it written in?
- Mainly Assembly, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The goal is a compiler that can compile GCC, from one kilobyte of hex
stage0 is a set of manually created hex programs in what the README calls a Cthulhu Path to madness fashion. The only goal is creating a bootstrapping path to a C compiler capable of compiling GCC, with the explicit requirement of a single 1 KByte binary or less.
There is a second condition that is unusual enough to be the project's real signature: all code must be able to be understood by 70 percent of the population of programmers. If the code cannot be understood by that volume, it needs to be altered until it satisfies the requirement.
That constraint is what makes stage0 different from a normal compiler project. A conventional bootstrap chain hides the earliest stages inside a prebuilt assembler or a firmware blob, and the guarantee of reproducibility starts from a trusted artefact you cannot audit. stage0 starts one level lower, with code small enough and plain enough to read, and the size limit keeps the trust root small enough to verify by hand.
The master repository for the work is at savannah.nongnu.org/projects/stage0, and the code is by Jeremiah Orians, copyright 2016. The licence is GPLv3 or later, and the README states that all code in the repository is under that licence.
The stages are a ladder, and each one adds one capability
The stage directories in the repository are the ladder, and the naming reflects what each one adds.
stage0 is described as the ultimate lowest level of bootstrap that is useful for systems without firmware, operating systems or any other provided software functionality. Those with such capabilities can skip this stage, since it requires human input.
The Hex0_monitor provides dual functionality: it assembles hex0 programs manually typed in, and it writes the characters, providing minimal text input functionality. The README explains why the distinction matters. The assembling is essential for creating the root binaries, and the character writing is essential for creating source files before you have an editor, and from that point the same tool is used as a minimal text editor until a more advanced text editor can be bootstrapped.
stage1 depends on the availability of text source files and at least a hex0 monitor or assembler. The steps in this stage can be fully automated if you trust the automation, or performed manually on any hardware you trust, and the requirement is that regardless of the method selected, the resulting binaries must be identical.
Inside stage1, the Hex0 assembler, or stage1_assembler-0, is the head node. Its functionality is reduced compared to the stage0 monitor because it only performs half of the required functions, generating binaries from hex0 source files. Its most important features of note are line comments with both a semicolon and a hash, since careful notes are essential for this stage.
Hex1, or stage1_assembler-1, is the next logical extension, adding single character labels and relative displacement using a prefix. Labels start with a colon, so the label a is written :a, and the prefix for relative offsets is an at sign, so the pointer must be written @a. Because of the mescc-tools standardisation of syntax, @label indicates a 16-bit relative displacement.
Hex2, or stage1_assembler-2 or hex2_linker, is described as as complex of a hex language that is both meaningful and worth the effort. Its advances over Hex1 are long labels, minimal 42 characters and ideally unlimited, absolute addressing with $label for 16-bit absolute addresses, and alternative pointer sizes with %label for 32-bit relative and &label for 32-bit absolute addresses. It may optionally support !label for 8-bit relative addressing and ?label for architecture specific sizes, and displacements such as @label1>label2 and %label1>label2 may be implemented where the architecture requires them for human readable hex2 source files such as ELF headers.
M0 exists to reduce the amount of hex you have to type
M0, also written as M0-macro or M1-macro, is the minimal string replacement program with string processing functionality required to convert an Assembly-like syntax into Hex2 programs that can be compiled. Its rules are merely an extension of Hex2 with the goal of reducing the amount of hex that one would need to write.
The three essential pieces are worth stating because they are the whole feature set. First, DEFINE STRING1 HEX_CHARACTERS, with no extra whitespace and no tab or newline inside the definition. Second, raw strings, which allow every character except the double quote, since there is no support for string escapes including NULL, and they are converted to hex characters for Hex2. Converting back adds a trailing NULL character or the number desired, with at least 1 and no upper bound, and restrictions such as padding to word boundaries are acceptable. Third, raw char strings, which pass anything inside them except the single quote that terminates the string.
By combining:label, @label, DEFINE SYSCALL 0F05, raw strings and chars, the amount of hex a person has to type drops sharply. That is the whole point of the stage, because the hex0 and hex1 stages are typed by hand on hardware that may have no other software at all.
The repository also carries a Knight Reference directory, and the Future section of the README mentions implementing the Knight processor in FPGA and then converting into TTL, which is where the hardware side of the project would go next.
Building it is one make target, and the dependencies are almost nothing
The build instructions are a single sentence. In order to build stage0 and all the pieces, one only needs to run make all. Each individual piece can be built by running make $piece with $piece replaced by the actual part you want to make.
The external dependency list is short, and the reason is that the whole project is about not depending on things. The only pieces that have any external dependencies are the Web IDE, which needs Python3 and CherryPy, libvm, which needs GCC, and vm, which needs GCC and GNU getopt. Everyone working in Python is pointed to knightpies by markjenkins, with the recommendation to check it out.
The repository uses submodules, so the clone command matters. The README says to clone the repository using git clone --recursive, and if you have already cloned it, run git submodule update --init, or after a pull be sure to run git submodule update --recursive.
The top level directory listing shows how much documentation is in here alongside the code: HACKING, Programming notes.org, questions_asked_by_new_people.org, bootstrapping Steps.org, CHANGELOG.org and the Knight Reference directory, plus a Library function prototypes directory and High_level_prototypes. The .org files are the working notes, and questions_asked_by_new_people.org is the onboarding document for anyone arriving at a project that begins with the word stage0.
The POSIX ports live in a separate repository, stage0-posix, for those wishing to work on POSIX ports of stage0, and the README notes that successful POSIX ports for x86, AMD64 and AArch64 exist in the POSIX submodule.
Where stage0 is the wrong project to adopt
The first wrong-tool case is the obvious one. Nobody should reach for stage0 to build software. It is not a compiler, not a build system, and not a library you depend on. The repository produces a set of tiny programs whose purpose is to enable a later stage, and a team that evaluates it as a toolchain will find that it is a research project with a specific goal.
The second is the human input requirement. The README is explicit that stage0 requires human input, and that those with firmware or an operating system can skip it. That is a deliberate design point rather than a missing feature, and it means the effort of stage0 is paid in typing hex by hand, on whatever minimal hardware you have, before anything else becomes possible. That effort is justified for a bootstrap research project and for a specific kind of teaching, and it is not justified for a commercial build pipeline.
The third is the ecosystem of the wider project. The README points to a bootstrapping wiki at bootstrapping.miraheze.org, a Libera.chat channel at #bootstrappable, and mentions there is easy work available for anyone wanting to do CPM/DOS porting. Contributions come through GitHub, GitLab, or email patches to Jeremiah. This is a volunteer-driven research programme with a large amount of unfinished ground to cover, and the Future section lists adding more ports to more hardware platforms as still to do.
The fourth is that stage0 is the floor, not the whole ladder. The repository holds stage0 through stage3 directories, but the README's own account describes the intended sequence rather than a completed chain, and the mescc-tools standardisation that Hex1 syntax depends on is an external dependency of the ecosystem, not of this repository.
Editorial conclusion
stage0 fits a person deliberately building a self-hosting toolchain from the bottom up, or a teaching project that wants to show what a compiler bootstrap actually consists of. It does not fit a team that needs a compiler, and it is not a build system anyone can adopt. Before spending time on it, read the CHANGELOG.org and the stage directories to see which stage is actually complete, because the project spans stage0 through stage3 and the README describes the intended path rather than a finished tool.
Frequently asked questions
What is the goal of the stage0 project?
The goal is creating a bootstrapping path to a C compiler capable of compiling GCC, using manually created hex programs, with the explicit requirement of a single 1 KByte binary or less. Additionaly, all code must be understandable by 70 percent of the population of programmers.
How do I build stage0?
Run make all to build stage0 and all the pieces, or make $piece for an individual part. The repository uses submodules, so clone it with git clone --recursive, or run git submodule update --init, and after a pull run git submodule update --recursive.
What is the difference between Hex0, Hex1 and Hex2?
Hex0 or stage1_assembler-0 is the head node of the stage1 bootstrap and only generates binaries from hex0 source files. Hex1 adds single character labels starting with a colon and relative displacement with an at sign prefix. Hex2, also the hex2_linker, adds long labels, absolute addressing with a dollar sign, and alternative pointer sizes.
What does the Hex0_monitor do?
It provides dual functionality: it assembles hex0 programs manually typed in, and it writes characters to provide minimal text input functionality. The assembling is essential for creating the root binaries, and the character writing covers creating source files before an editor exists.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/oriansj-stage0)Was this useful?