From 0f854031971cc0bb6df58880803dba1c548d56ba Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 21:14:01 +0200 Subject: [PATCH 1/7] The dependency rule: Rust and QEMU, and beside them only C and C++ tools ToyOS can one day build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The owner ruled (2026-09-29), confirmed as "yes thats the rule we want": Rust and QEMU for development, and beside them only tools built from C or C++ source that ToyOS can one day build and run itself — Python, Perl, CMake, Ninja, make — each declared, and taken only where no Rust tool does the job. No binary that exists for one host OS alone: a macOS binary is a hard no. ToyOS's own code is Rust; it writes no Python, Perl or shell of its own. CLAUDE.md's Dependencies paragraph states it, pointing at `check_prerequisites` for the declared tools. Its standing failures are now what the rule still refuses: the two macOS FAT tools, and `diag/flash.sh`, the one shell file `git ls-files '*.sh' '*.py' '*.pl'` lists. Python via `rust/x` and `cc` for every host link stop being failures; they are declared C and C++ tools. The reviewer's Arrivals rule becomes the same rule: a host tool outside Rust and QEMU is a C or C++ tool ToyOS can one day build, declared in `check_prerequisites` and in the issue, with the reason no Rust tool does the job in the PR; a binary for one host OS alone, or new Python, Perl or shell of ToyOS's own, is a BLOCKER. `issues/build/python-and-cc-are-declared.md` becomes `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`: per tool (Python, `cc`, CMake and Ninja), where it runs and why no Rust tool does the job, with one exit for the four — it builds and runs on ToyOS. Deleted as stale under the rule: the Rust bootstrap in the fork as Python's only exit, the "hole" framing, the 2026-08-08 and 2026-09-01 rulings, the Ubuntu version pins that `nightly.yml` carries, and the pointer to the two macOS issues, which are CLAUDE.md's now. `git` joins the list of what else is run, `gh` is marked Go and so outside the rule. Perl and `make` are not listed: nothing on main runs them. The one citation, in `issues/build/toyos-builds-itself.md`, follows the rename. README's Prerequisites loses the sentence that called the four tools `rustc`'s and not ToyOS's. Co-Authored-By: Claude Opus 5.5 --- .claude/agents/reviewer.md | 10 +- CLAUDE.md | 4 +- README.md | 3 +- issues/build/python-and-cc-are-declared.md | 121 ------------------ ...-c-and-cxx-tools-toyos-does-not-yet-run.md | 68 ++++++++++ issues/build/toyos-builds-itself.md | 3 +- 6 files changed, 78 insertions(+), 131 deletions(-) delete mode 100644 issues/build/python-and-cc-are-declared.md create mode 100644 issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index cdc50feddcb..448846cd5d6 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -50,11 +50,11 @@ above; otherwise it is a NOTE. `arch::aarch64` in no generic kernel code; and none of them in a crate whose manifest `description` says pure. A `4096` in the kernel that means a page is a private copy of `mm::PAGE_SIZE`. -- **Arrivals.** A binary outside Rust's toolchain, git, QEMU and this repository's own Rust is - refused, whether the host starts it — `Command::new`, `libc::system`, an `exec` or - `posix_spawn`, a tool a build script or `cc::Build` drives — or `.github/` installs it, by - whatever manager or `sh -c`. The ones that stand are those - `issues/build/python-and-cc-are-declared.md` declares. +- **Arrivals.** A host tool outside Rust and QEMU, however started or installed, is a C or C++ + tool ToyOS can one day build, declared in `check_prerequisites` and + `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`; the PR says why no + Rust tool does the job. BLOCKER: a binary for one host OS alone; new Python, Perl or shell of + ToyOS's own. A third-party action `main` does not use is refused, and every `uses:` pins a 40-hex commit with its tag in a trailing comment or names a local path that resolves. A file added to or deleted from `tests/testcases/tinycc/` moves the count diff --git a/CLAUDE.md b/CLAUDE.md index 81c8f5f4df0..48b0a5ba077 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,11 +58,11 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -Only **Rust** and **QEMU** (for development), on any host OS and architecture — the development machine is nothing special. The rules: no binary outside those two — a macOS binary is a hard no, and "only for tests" does not soften it; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; no Python; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special — and beside them only C or C++ tools ToyOS can one day build and run, each declared in `check_prerequisites` and taken where no Rust tool does the job. The rules: no binary for one host OS alone — a macOS binary is a hard no, and "only for tests" does not soften it; no Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. -The bar is not yet the tree. The standing failures are declared rather than removed — Python via `rust/x`, `cc` for every host link, two macOS FAT tools. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. +The bar is not yet the tree. The standing failures are the two macOS FAT tools and `diag/flash.sh`, our own shell. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. - **toyos-ld** — frozen: everything links with rust-lld, and toyos-ld stays only as the linker inside ToyOS until lld runs there, then goes. - **rust/** — Rust compiler/std fork with ToyOS platform support (submodule). Auto-bootstraps; kept current with upstream. Its rules: `.claude/agents/implementer.md`, "A fork". diff --git a/README.md b/README.md index 23e8468bd21..41ce81f11bf 100644 --- a/README.md +++ b/README.md @@ -225,8 +225,7 @@ same font the kernel blits. - A C compiler on `PATH` as `cc`, and a Python 3 - CMake and Ninja -The last two lines are `rustc`'s and not ToyOS's, and nothing that boots touches -them. `rustc` links every **host** binary through `cc`, which rustup does not +`rustc` links every **host** binary through `cc`, which rustup does not install. `rust/x`, the entry point to rustc's own bootstrap, is a shell script whose whole job is to find a Python to run `bootstrap.py` with — so a clean clone needs one, and so does every toolchain change. And that bootstrap builds diff --git a/issues/build/python-and-cc-are-declared.md b/issues/build/python-and-cc-are-declared.md deleted file mode 100644 index cc45f0c0939..00000000000 --- a/issues/build/python-and-cc-are-declared.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -status: open -kind: tooling -opened: 2026-08-08 ---- - -# Every toolchain build runs Python, CMake and Ninja, and every host link runs `cc` - -**The owner ruled on 2026-08-08: *"its required by rusts toolchain i guess we can -be transparent about that."*** Both are named in the README's Prerequisites -section and by `check_prerequisites` in `src/main.rs`, which is now two lists — -`REQUIRED`, which exits (`git`, `rustup`, `qemu-system-x86_64`, `cc`), and -`ALSO_USED`, which names what is absent and continues (a Python, `df`, `ps`, -`find`). The README's opening no longer claims Rust and QEMU are the whole -setup. - -**The entry stays open because declaring is not removing.** The hole is the -same size: `bootstrap.py` still cannot run inside ToyOS, and the second option -below — a Rust bootstrap in the `rust/` fork — is still the only thing that -closes it. - -Two details the fix had to get right. The preflight looks for *any* of -`python3 python py python2 uv`, because that is what `rust/x` searches and a -machine with only `python` builds fine; and it scans `PATH` rather than running -`--version`, because asking macOS for `py` opens the Command Line Tools -installer. `cc` is stated with its scope attached wherever it appears — no guest -binary links through it — because *"ToyOS needs a C compiler"* is false and -reads as a far larger claim than the truth. - -This is the entry that says the two largest holes in *"Rust and QEMU, one -command"* are real, and what follows is the whole of both. - -**The owner ruled on 2026-09-01: it stays declaration-only, and it stays -open.** Closing the Python half means a Rust bootstrap inside the `rust/` fork — -a large delta carried against upstream forever, for no product benefit today. -That is a real cost and this is a real hole, so the entry is not downgraded: it -remains a present-state weakness on the self-hosting track, to be sequenced when -that track is funded rather than taken opportunistically. Do not propose the -Rust bootstrap again as an incidental fix; do not soften the entry either. - -`src/toolchain.rs:749` picks `./x` when `rust/x` exists, which it does. That file -is a `/bin/sh` script whose whole job is `SEARCH="python3 python py python2 uv"`, -and it execs `x.py` → `rust/src/bootstrap/bootstrap.py`. So a clean -clone cannot build a toolchain without Python 3. It is upstream's bootstrap and -not our code, which is why it is stated rather than blamed — but the bar has no -upstream exemption, and `bootstrap.py` can never run inside ToyOS. - -Separately, and measured with `rustup run toyos rustc --print link-args` on a -trivial host binary: rustc invokes `"cc"` and sets -`SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`. rustup installs -neither. Every *host* binary goes through it — the build system, the harness, -`toyos-ld`, rustc stage2, clang. **No guest binary does**: every guest binary -links through the toolchain's `rust-lld`, so nothing that boots is touched. - -The cheap half of the fix — a preflight and a README that say what the machine -actually needs — is done. `REQUIRED` carries `cc` and `ALSO_USED` carries the -Python search list (`src/main.rs:18`, `:28`). The expensive half is untouched. - -**CMake and Ninja joined the list on 2026-09-27, by the owner's ruling**: rustc's -LLVM is built from source, from `ToyOSOrg/llvm-project`, with clang beside it, -and rustc's bootstrap builds LLVM with CMake driving Ninja. Both are declared -where the others are — CMake in `REQUIRED` in `src/main.rs`, because every -build keys the host's LLVM on `cmake --version` (`src/llvm.rs`), and Ninja in -`ALSO_USED`, because a build whose LLVM this host has already built runs it -not — and in the README's Prerequisites. On macOS they come from Homebrew (`brew install cmake ninja`), -with no workaround; on the nightly's toolchain runner at the versions -`.github/workflows/nightly.yml` pins from Ubuntu 24.04's archive (`cmake -3.28.3-1build7`, `ninja-build 1.11.1-2`); the two portability jobs install -their platform's own, which is their premise. Neither reaches a guest. The -exit condition is Python's: they go when the build no longer needs a host, -which is the self-hosting track's last stage -(`issues/build/toyos-builds-itself.md`). - -**What removing each takes.** - -- **Python.** Upstream has no Python-free entry: `x`, `x.py` and - `src/tools/x` all end in `bootstrap.py`. But `src/bootstrap` builds with - rustup's stable cargo, `--locked`, and no Python, and the binary downloads - its own stage0 (`download_beta_toolchain`) and looks for a Python only to run - tests. So `src/toolchain.rs` could build and run it in place of - `bootstrap.py`, with no change to the fork, taking over `bootstrap.py`'s - environment contract at every fork bump. That removes Python only from a - build that reuses a keyed LLVM: LLVM's own CMake requires a Python 3 - (`find_package(Python3 … REQUIRED)`), so building an LLVM needs one until CMake goes. -- **`cc` has two jobs**: it links every host binary, and it is - the C++ compiler of LLVM, clang, LLD and `rustc_llvm` (`bootstrap.toml`'s - `cc`/`cxx`, named in `src/llvm.rs`, with `xcrun` asked for the SDK). It also - compiles `ring`'s C for `tests/https-server-host` and - `tests/https-fetch-host`. `rust-lld` can take only the link. Nothing replaces the compile but a clang the host did not build. -- **CMake and Ninja.** LLVM, clang and LLD are described in CMake. The only other build - descriptions upstream carries are an unsupported GN overlay (`BUILD.gn`) - and a Bazel one. Replacing CMake means writing one of those and keeping it - in Rust, which is M5's. - -**Every other binary outside Rust and QEMU that this tree runs is declared -here too**, because a reviewer refuses any one that is not -(`.claude/agents/reviewer.md`, Arrivals). `newfs_msdos` and `hdiutil` are -`issues/filesystem/fat32-suite-needs-macos-binaries.md`'s, and `diskutil` and -`plutil` are `issues/build/the-owners-flash-script-runs-diskutil.md`'s. - -- **`gh`** — `src/release.rs` asks GitHub whether a toolchain release exists, - creates it and moves the `sdk-` alias with it, on a runner only. - Exit: `src/release.rs` speaks GitHub's REST API itself. -- **`curl`**, and **`ca-certificates`**, the trust store it verifies against — - `src/release.rs` downloads the toolchain release, `src/sdkversion.rs` asks - the crates.io index, and the nightly's container and macOS jobs fetch - `rustup-init.sh` with it. Exit: those fetches are Rust's, and a job - installs rustup without it. -- **`tar`** and **`zstd`** — `src/release.rs` packs and unpacks the toolchain - release. Exit: both are done in Rust, in-process. -- **`ssh`** — `src/metal.rs` reaches the T14's Ubuntu with it, only when the - metal loop is asked for. Exit: that loop drives the repository's own russh - client, `crate::build::ssh_client_host`, which `src/metaltalk.rs` already - drives at a booted T14. -- **`ovmf-generic`** — the guest container's UEFI firmware - (`src/firmware.rs`), which Debian packages apart from QEMU. Exit: the - instrument's QEMU carries its own firmware. -- **`build-essential`** — Debian's package for `cc` and `c++`, which the - nightly's guest containers and `portability-linux` install: every host - binary those jobs build links through `cc`, `ring`'s C compiles with it, and - `portability-linux` builds LLVM with `c++`. Exit: it goes with `cc`. diff --git a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md new file mode 100644 index 00000000000..078c05c5232 --- /dev/null +++ b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md @@ -0,0 +1,68 @@ +--- +status: open +kind: tooling +opened: 2026-09-29 +--- + +# The build runs C and C++ tools that ToyOS does not yet build and run + +Each is declared by `check_prerequisites` in `src/main.rs` — `REQUIRED`, which +exits, and `ALSO_USED`, which names what is absent and continues — and in the +README's Prerequisites. None reaches a guest. **Exit, for each of the four +below**: it builds and runs on ToyOS, on the self-hosting track +(`issues/build/toyos-builds-itself.md`). + +- **Python.** `rust/x` is a `/bin/sh` script whose whole job is to find one of + `python3 python py python2 uv` and exec `x.py`, which ends in + `rust/src/bootstrap/bootstrap.py`; `src/toolchain.rs` picks `./x` when it + exists. So a clean clone cannot build a toolchain without Python 3. The + preflight looks for any of those names because that is what `rust/x` searches, + and scans `PATH` rather than running `--version` because asking macOS for `py` + opens the Command Line Tools installer. No Rust tool does the job: upstream + has no Python-free entry (`x`, `x.py` and `src/tools/x` all end in + `bootstrap.py`); `src/bootstrap` builds with rustup's stable cargo and no + Python, but running it in place of `bootstrap.py` has `src/toolchain.rs` take + over `bootstrap.py`'s environment contract at every fork bump; and LLVM's own + CMake requires a Python 3 (`find_package(Python3 … REQUIRED)`) whichever + starts the build. +- **`cc`** has two jobs. It links every host binary — the build system, the + harness, `toyos-ld`, rustc stage2, clang — and rustc sets `SDKROOT` for it; + no guest binary links through it, every one links through the toolchain's + `rust-lld`. And it is the C++ compiler of LLVM, clang, LLD and `rustc_llvm` + (`bootstrap.toml`'s `cc`/`cxx`, named in `src/llvm.rs`, with `xcrun` asked for + the SDK), and compiles `ring`'s C for `tests/https-server-host` and + `tests/https-fetch-host`. No Rust tool does the job: `rust-lld` can take only + the link, and nothing replaces the compile but a clang the host did not build. +- **CMake and Ninja.** rustc's bootstrap builds LLVM and clang from + `ToyOSOrg/llvm-project` with CMake driving Ninja, whenever this host has not + built that LLVM. CMake is in `REQUIRED` because every build keys the host's + LLVM on `cmake --version` (`src/llvm.rs`); Ninja is in `ALSO_USED` because a + build whose LLVM is already built does not run it. No Rust tool does the job: + LLVM, clang and LLD are described in CMake, and the only other descriptions + upstream carries are an unsupported GN overlay (`BUILD.gn`) and a Bazel one. + +**Also run, and declared here:** + +- **`git`** — `REQUIRED`: every build, and the image ships what git says is + tracked. +- **`gh`** — Go, so outside the rule. `src/release.rs` asks GitHub whether a + toolchain release exists, creates it and moves the `sdk-` alias with + it, on a runner only. Exit: `src/release.rs` speaks GitHub's REST API itself. +- **`curl`**, and **`ca-certificates`**, the trust store it verifies against — + `src/release.rs` downloads the toolchain release, `src/sdkversion.rs` asks + the crates.io index, and the nightly's container and macOS jobs fetch + `rustup-init.sh` with it. Exit: those fetches are Rust's, and a job + installs rustup without it. +- **`tar`** and **`zstd`** — `src/release.rs` packs and unpacks the toolchain + release. Exit: both are done in Rust, in-process. +- **`ssh`** — `src/metal.rs` reaches the T14's Ubuntu with it, only when the + metal loop is asked for. Exit: that loop drives the repository's own russh + client, `crate::build::ssh_client_host`, which `src/metaltalk.rs` already + drives at a booted T14. +- **`ovmf-generic`** — the guest container's UEFI firmware + (`src/firmware.rs`), which Debian packages apart from QEMU. Exit: the + instrument's QEMU carries its own firmware. +- **`build-essential`** — Debian's package for `cc` and `c++`, which the + nightly's guest containers and `portability-linux` install: every host + binary those jobs build links through `cc`, `ring`'s C compiles with it, and + `portability-linux` builds LLVM with `c++`. Exit: it goes with `cc`. diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index f784c60c289..c9911e88d24 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -37,7 +37,8 @@ AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track. - **M5 — ToyOS rebuilds its own compilers to a fixed point; the host is no longer needed.** The guest's toolchain builds the next toolchain, and that one builds itself again to the same bytes. Python (`bootstrap.py`), CMake and - Ninja leave the build (`issues/build/python-and-cc-are-declared.md`). + Ninja leave the build + (`issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`). *Exit*: the fixed point, reached with no host in the loop. **Blocked on other tracks.** M2 needs packages over HTTPS From d1410849d55e5e4eb84f07d715e5e4fa876058f3 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 21:31:39 +0200 Subject: [PATCH 2/7] The dependency rule: the standing failures are all of them, and what the rule made false goes CLAUDE.md's Dependencies paragraph loses "Ask of anything new: could this ever run inside ToyOS?", which "tools ToyOS can one day build and run" now says, and its new clause is tightened. Its standing failures now name every use the rule refuses, each read in the code first: `newfs_msdos` and `hdiutil` (`toyos-fat32/tests/common/mod.rs`), macOS's `xcrun` (`src/llvm.rs`, which asks it for the SDK on an apple-darwin host), Go's `gh` (`src/release.rs`, three call sites) and `diag/flash.sh`, the one shell file `git ls-files '*.sh' '*.py' '*.pl'` lists. The issue that lists the C and C++ tools gains an `xcrun` entry with its exit, so the failure CLAUDE.md names is recorded, and `xcrun` leaves the `cc` entry it was a clause of. Deleted, because the rule made them false: - `issues/build/toyos-builds-itself.md`, M5: "Python (`bootstrap.py`), CMake and Ninja leave the build (...)". They are not to leave; the track's exit is the fixed point with no host in the loop. - `issues/build/the-owners-flash-script-runs-diskutil.md`: "None of these is in CLAUDE.md's standing failures." `diag/flash.sh` is. - `README.md`: "no system linker". The Prerequisites below it say `rustc` links every host binary through `cc`. "No Make" stays: nothing on main runs `make` (`rg -n 'Command::new\("make"\)' src tests kernel userland` and `rg -n -w make .github` both exit 1). Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 4 ++-- README.md | 2 +- ...ild-runs-c-and-cxx-tools-toyos-does-not-yet-run.md | 11 +++++++---- issues/build/the-owners-flash-script-runs-diskutil.md | 3 +-- issues/build/toyos-builds-itself.md | 4 +--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 48b0a5ba077..b3476144f09 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,11 +58,11 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special — and beside them only C or C++ tools ToyOS can one day build and run, each declared in `check_prerequisites` and taken where no Rust tool does the job. The rules: no binary for one host OS alone — a macOS binary is a hard no, and "only for tests" does not soften it; no Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run, declared in `check_prerequisites`. No binary for one host OS alone — a macOS binary is a hard no, and "only for tests" does not soften it; no Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. -The bar is not yet the tree. The standing failures are the two macOS FAT tools and `diag/flash.sh`, our own shell. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. +The bar is not yet the tree. The standing failures are the two macOS FAT tools, macOS's `xcrun`, Go's `gh` and our own shell `diag/flash.sh`. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. - **toyos-ld** — frozen: everything links with rust-lld, and toyos-ld stays only as the linker inside ToyOS until lld runs there, then goes. - **rust/** — Rust compiler/std fork with ToyOS platform support (submodule). Auto-bootstraps; kept current with upstream. Its rules: `.claude/agents/implementer.md`, "A fork". diff --git a/README.md b/README.md index 41ce81f11bf..670bfac6b13 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ cargo run ``` One command, and a complete OS boots. No Make, no Docker, no LLVM to install, -no cross-toolchain to assemble, no system linker. Everything that boots is +no cross-toolchain to assemble. Everything that boots is built by a toolchain in this repository. Rust and QEMU, plus the four things `rustc`'s own bootstrap needs on every diff --git a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md index 078c05c5232..93fd768e3de 100644 --- a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md +++ b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md @@ -29,10 +29,10 @@ below**: it builds and runs on ToyOS, on the self-hosting track harness, `toyos-ld`, rustc stage2, clang — and rustc sets `SDKROOT` for it; no guest binary links through it, every one links through the toolchain's `rust-lld`. And it is the C++ compiler of LLVM, clang, LLD and `rustc_llvm` - (`bootstrap.toml`'s `cc`/`cxx`, named in `src/llvm.rs`, with `xcrun` asked for - the SDK), and compiles `ring`'s C for `tests/https-server-host` and - `tests/https-fetch-host`. No Rust tool does the job: `rust-lld` can take only - the link, and nothing replaces the compile but a clang the host did not build. + (`bootstrap.toml`'s `cc`/`cxx`, named in `src/llvm.rs`), and compiles `ring`'s + C for `tests/https-server-host` and `tests/https-fetch-host`. No Rust tool + does the job: `rust-lld` can take only the link, and nothing replaces the + compile but a clang the host did not build. - **CMake and Ninja.** rustc's bootstrap builds LLVM and clang from `ToyOSOrg/llvm-project` with CMake driving Ninja, whenever this host has not built that LLVM. CMake is in `REQUIRED` because every build keys the host's @@ -48,6 +48,9 @@ below**: it builds and runs on ToyOS, on the self-hosting track - **`gh`** — Go, so outside the rule. `src/release.rs` asks GitHub whether a toolchain release exists, creates it and moves the `sdk-` alias with it, on a runner only. Exit: `src/release.rs` speaks GitHub's REST API itself. +- **`xcrun`** — macOS's, so outside the rule. On macOS `src/llvm.rs` asks it for + the SDK's path and version, which the LLVM's key names. Exit: the key names + the SDK without asking `xcrun`. - **`curl`**, and **`ca-certificates`**, the trust store it verifies against — `src/release.rs` downloads the toolchain release, `src/sdkversion.rs` asks the crates.io index, and the nightly's container and macOS jobs fetch diff --git a/issues/build/the-owners-flash-script-runs-diskutil.md b/issues/build/the-owners-flash-script-runs-diskutil.md index 120ea0913cd..4284418f1c3 100644 --- a/issues/build/the-owners-flash-script-runs-diskutil.md +++ b/issues/build/the-owners-flash-script-runs-diskutil.md @@ -8,8 +8,7 @@ opened: 2026-09-29 `diag/flash.sh` writes an image to a USB stick through `diskutil` and `plutil`, which are macOS binaries, and through `shasum`, `dd` and `sudo`. The README's -flashing steps also run `diskutil`. None of these is in CLAUDE.md's standing -failures. The metal loop does not use this script: it flashes +flashing steps also run `diskutil`. The metal loop does not use this script: it flashes the T14's stick over `ssh` from Ubuntu. The script's two gates are what keep it off an internal drive: it takes only diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index c9911e88d24..96df8041b44 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -36,9 +36,7 @@ AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track. the host build of the same commit. - **M5 — ToyOS rebuilds its own compilers to a fixed point; the host is no longer needed.** The guest's toolchain builds the next toolchain, and that - one builds itself again to the same bytes. Python (`bootstrap.py`), CMake and - Ninja leave the build - (`issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`). + one builds itself again to the same bytes. *Exit*: the fixed point, reached with no host in the loop. **Blocked on other tracks.** M2 needs packages over HTTPS From a9faca9ff4d41d69377ce1785aebf346df97fb38 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 21:41:27 +0200 Subject: [PATCH 3/7] Removing machinery updates every prompt that names it, and running agents are told The owner's second ruling of 2026-09-29: "i think it makes sense that the tracks get the improvements we are working on as theyre landing. if we remove machinery we need to tell them how to do it right afterwards." reviewer.md gains an Instructions rule: a change that removes or renames a command, flag or step an agent runs updates every prompt that names it, each `CLAUDE.md` and `.claude/agents/*.md`, in the same diff, saying what to do instead; an instruction left pointing at what is gone is a BLOCKER. It sits directly before Arrivals. orchestrator.md's Land section gains one sentence after "sync the primary checkout": when a landing changes how agents work, every running agent is told the new way in one line before its next round, and merges main before its final gate. `wc -w`: reviewer.md 1443 to 1491, orchestrator.md 863 to 892. Co-Authored-By: Claude Opus 5.5 --- .claude/agents/orchestrator.md | 6 ++++-- .claude/agents/reviewer.md | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.claude/agents/orchestrator.md b/.claude/agents/orchestrator.md index bd5330801d6..377ce8d957e 100644 --- a/.claude/agents/orchestrator.md +++ b/.claude/agents/orchestrator.md @@ -53,8 +53,10 @@ settles it and decide. Glance before every merge: the title and body as `main`'s record, the diff's size against the brief's fence, tests added or deleted, CI. Then `gh pr ready` and `gh pr merge --auto --merge`. -After a landing, sync the primary checkout. A red that is not about the diff is fixed at its -owner, never re-run away, and nothing but a defect may turn `main` red. +After a landing, sync the primary checkout. When a landing changes how agents work, every running +agent is told the new way in one line before its next round, and merges main before its final gate. +A red that is not about the diff is fixed at its owner, never re-run away, and nothing but a defect +may turn `main` red. A fix for a red lands ahead of feature work. A nightly name red three nights running gets an owner issue that day, and is deleted if nobody owns it a week later. diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index 448846cd5d6..a5de56f2671 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -50,6 +50,9 @@ above; otherwise it is a NOTE. `arch::aarch64` in no generic kernel code; and none of them in a crate whose manifest `description` says pure. A `4096` in the kernel that means a page is a private copy of `mm::PAGE_SIZE`. +- **Instructions.** A change that removes or renames a command, flag or step an agent runs updates + every prompt that names it — each `CLAUDE.md` and `.claude/agents/*.md` — in the same diff, + saying what to do instead; an instruction left pointing at what is gone is a BLOCKER. - **Arrivals.** A host tool outside Rust and QEMU, however started or installed, is a C or C++ tool ToyOS can one day build, declared in `check_prerequisites` and `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`; the PR says why no From 714a600699cb8896f143cd52ee5f76a767fd2196 Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 23:01:55 +0200 Subject: [PATCH 4/7] Answer the first review of #632: one declaration of every host tool, and the rulings as written MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md states the rule and lists nothing. Dependencies carries the ruling's examples (Python, Perl, CMake, Ninja, make) and "each declared"; "declared in `check_prerequisites`" goes, because `--ci` and the metal loop run tools where `check_prerequisites` never runs. The standing-failures list goes too: the bar sentence now points at reviewer.md's Arrivals as where every host tool and every standing failure is declared, since a CLAUDE.md cites no issue file and holds no list another source answers. To stay at main's 2614 words (`wc -w`), "nothing — build, test, or verification — rests on a host binary. Self-hosting means" is deleted: the ruling's "tools ToyOS can one day build and run" is that north star as a test, and the self-hosting sentence keeps its definition. reviewer.md, Arrivals, is the one pointer: it names the ways a tool arrives that a reviewer searches (`Command::new`, `libc::system`, `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` package manager, `sh -c`), names the issue as the only place a host tool is declared, keeps the ruling's "and run", and makes each of five arrivals a BLOCKER: an undeclared host tool, one not built from C or C++ source ToyOS can one day build and run (Go's `gh`), a binary for one host OS alone, a C or C++ tool taken where a Rust tool does the job, and new Python, Perl or shell of ToyOS's own. Instructions says an instruction naming what is gone is not the prose "Prose is removed, never reviewed" governs, so a stale one is a BLOCKER there and not a citation here. orchestrator.md: a running agent is told the new way in one line and merges main before its next round, because until that merge its worktree still has the removed machinery and refuses the new flag. implementer.md, at the orchestrator's request: never run `git submodule` in a linked worktree. One in another worktree wrote a `core.worktree` that does not exist into the primary's `.git/modules/rust/config`, and every git command in the primary's `rust/` failed until it was restored. The declaration, issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md, is now a table of every tool main's build, tests, workflows and metal loop run outside Rust and QEMU, found by those arrival paths over src/, tests/, kernel/, userland/, toyos-*/, .github/ and diag/: where each runs, admitted or refused with the reason, and its exit. 28 rows, 10 admitted and 18 refused. Python is admitted for LLVM's CMake (`find_package(Python3 … REQUIRED)`); `rust/x` and `bootstrap.py` are refused, because upstream's bootstrap binary does their job. Apple's `cc`, `c++`, `ar` and `xcrun` are refused as one host OS's, with M5 as their exit. The T14 bench's Ubuntu tools are admitted until Ubuntu leaves the loop. The four multi-command nightly steps and the metal loop's `umask 077 && cat >` are shell of our own. The FAT and flash issues are named again as their tools' exits. What repeated src/main.rs is gone. toyos-builds-itself.md, M5, says its LLVM runs Python, CMake and Ninja built for ToyOS, so the declaration's exit for those three names a stage. Deleted as the review asked: nightly.yml's "Only Rust and QEMU" quote, the FAT issue's sentence calling the replaced rule the owner's, and ", and no ledger declares it" from the flash issue's title. Co-Authored-By: Claude Opus 5.5 --- .claude/agents/implementer.md | 3 +- .claude/agents/orchestrator.md | 2 +- .claude/agents/reviewer.md | 14 +-- .github/workflows/nightly.yml | 5 +- CLAUDE.md | 4 +- ...-c-and-cxx-tools-toyos-does-not-yet-run.md | 97 +++++++------------ .../the-owners-flash-script-runs-diskutil.md | 2 +- issues/build/toyos-builds-itself.md | 5 +- .../fat32-suite-needs-macos-binaries.md | 4 +- 9 files changed, 55 insertions(+), 81 deletions(-) diff --git a/.claude/agents/implementer.md b/.claude/agents/implementer.md index 4b1b82fc040..a4d1bb91c6a 100644 --- a/.claude/agents/implementer.md +++ b/.claude/agents/implementer.md @@ -55,7 +55,8 @@ Fork sources live outside this repository: a search for callers must also cover ## Commits and the pull request `git commit -F `, never `-m`. No `--amend`, no rebase, no force: merge `origin/main`, never -rebase onto it. Never touch `toyos-abi/src`, `toyos/src` or `userland/libc/src` unless the brief is +rebase onto it. Never run `git submodule` in a linked worktree: it writes `core.worktree` into the +fork's shared config and breaks git in the primary checkout's `rust/`. Never touch `toyos-abi/src`, `toyos/src` or `userland/libc/src` unless the brief is an ABI brief. No new dependency. Push from your branch, never `main`, with `git status --porcelain` empty: `git push -u origin diff --git a/.claude/agents/orchestrator.md b/.claude/agents/orchestrator.md index 377ce8d957e..5048154f81d 100644 --- a/.claude/agents/orchestrator.md +++ b/.claude/agents/orchestrator.md @@ -54,7 +54,7 @@ settles it and decide. Glance before every merge: the title and body as `main`'s record, the diff's size against the brief's fence, tests added or deleted, CI. Then `gh pr ready` and `gh pr merge --auto --merge`. After a landing, sync the primary checkout. When a landing changes how agents work, every running -agent is told the new way in one line before its next round, and merges main before its final gate. +agent is told the new way in one line and merges main before its next round. A red that is not about the diff is fixed at its owner, never re-run away, and nothing but a defect may turn `main` red. A fix for a red lands ahead of feature work. A nightly name red three nights running gets an owner diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index a5de56f2671..050c71e05e8 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -52,12 +52,14 @@ above; otherwise it is a NOTE. A `4096` in the kernel that means a page is a private copy of `mm::PAGE_SIZE`. - **Instructions.** A change that removes or renames a command, flag or step an agent runs updates every prompt that names it — each `CLAUDE.md` and `.claude/agents/*.md` — in the same diff, - saying what to do instead; an instruction left pointing at what is gone is a BLOCKER. -- **Arrivals.** A host tool outside Rust and QEMU, however started or installed, is a C or C++ - tool ToyOS can one day build, declared in `check_prerequisites` and - `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md`; the PR says why no - Rust tool does the job. BLOCKER: a binary for one host OS alone; new Python, Perl or shell of - ToyOS's own. + saying what to do instead. Such an instruction is not the prose "Prose is removed, never + reviewed" governs: one left naming what is gone is a BLOCKER. +- **Arrivals.** A host tool outside Rust and QEMU arrives by `Command::new`, `libc::system`, + `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` package manager or `sh -c`, + and is declared in `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md` and + nowhere else. A BLOCKER each: an undeclared host tool; one, like Go's `gh`, not built from C or + C++ source ToyOS can one day build and run; a binary for one host OS alone; a C or C++ tool + taken where a Rust tool does the job; new Python, Perl or shell of ToyOS's own. A third-party action `main` does not use is refused, and every `uses:` pins a 40-hex commit with its tag in a trailing comment or names a local path that resolves. A file added to or deleted from `tests/testcases/tinycc/` moves the count diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3056dd3ff57..621c74fd650 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -178,9 +178,8 @@ jobs: key: guest-${{ github.run_id }} - *serial - # "Only Rust and QEMU", run rather than argued: `cargo run -- --build-only` - # from a fresh machine. `sid` as it stands, image and archive both, and no - # cache — a fresh machine is the premise. + # `cargo run -- --build-only` from a fresh machine. `sid` as it stands, + # image and archive both, and no cache — a fresh machine is the premise. portability-linux: runs-on: ubuntu-24.04 timeout-minutes: 350 diff --git a/CLAUDE.md b/CLAUDE.md index b3476144f09..f1837763852 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,11 +58,11 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run, declared in `check_prerequisites`. No binary for one host OS alone — a macOS binary is a hard no, and "only for tests" does not soften it; no Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. No Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. -The bar is not yet the tree. The standing failures are the two macOS FAT tools, macOS's `xcrun`, Go's `gh` and our own shell `diag/flash.sh`. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. +The bar is not yet the tree: `.claude/agents/reviewer.md`, "Arrivals", says where every host tool and every standing failure is declared. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. - **toyos-ld** — frozen: everything links with rust-lld, and toyos-ld stays only as the linker inside ToyOS until lld runs there, then goes. - **rust/** — Rust compiler/std fork with ToyOS platform support (submodule). Auto-bootstraps; kept current with upstream. Its rules: `.claude/agents/implementer.md`, "A fork". diff --git a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md index 93fd768e3de..3646f3ea2e2 100644 --- a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md +++ b/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md @@ -6,66 +6,39 @@ opened: 2026-09-29 # The build runs C and C++ tools that ToyOS does not yet build and run -Each is declared by `check_prerequisites` in `src/main.rs` — `REQUIRED`, which -exits, and `ALSO_USED`, which names what is absent and continues — and in the -README's Prerequisites. None reaches a guest. **Exit, for each of the four -below**: it builds and runs on ToyOS, on the self-hosting track -(`issues/build/toyos-builds-itself.md`). +Every tool `main`'s build, tests, workflows and metal loop run outside Rust and +QEMU, found by the ways `.claude/agents/reviewer.md`'s Arrivals names, with the +verdict of `CLAUDE.md`'s Dependencies on each; a refused row is a standing +failure. A workflow's package manager, `apt-get` or `brew`, is how a row +arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itself.md`. -- **Python.** `rust/x` is a `/bin/sh` script whose whole job is to find one of - `python3 python py python2 uv` and exec `x.py`, which ends in - `rust/src/bootstrap/bootstrap.py`; `src/toolchain.rs` picks `./x` when it - exists. So a clean clone cannot build a toolchain without Python 3. The - preflight looks for any of those names because that is what `rust/x` searches, - and scans `PATH` rather than running `--version` because asking macOS for `py` - opens the Command Line Tools installer. No Rust tool does the job: upstream - has no Python-free entry (`x`, `x.py` and `src/tools/x` all end in - `bootstrap.py`); `src/bootstrap` builds with rustup's stable cargo and no - Python, but running it in place of `bootstrap.py` has `src/toolchain.rs` take - over `bootstrap.py`'s environment contract at every fork bump; and LLVM's own - CMake requires a Python 3 (`find_package(Python3 … REQUIRED)`) whichever - starts the build. -- **`cc`** has two jobs. It links every host binary — the build system, the - harness, `toyos-ld`, rustc stage2, clang — and rustc sets `SDKROOT` for it; - no guest binary links through it, every one links through the toolchain's - `rust-lld`. And it is the C++ compiler of LLVM, clang, LLD and `rustc_llvm` - (`bootstrap.toml`'s `cc`/`cxx`, named in `src/llvm.rs`), and compiles `ring`'s - C for `tests/https-server-host` and `tests/https-fetch-host`. No Rust tool - does the job: `rust-lld` can take only the link, and nothing replaces the - compile but a clang the host did not build. -- **CMake and Ninja.** rustc's bootstrap builds LLVM and clang from - `ToyOSOrg/llvm-project` with CMake driving Ninja, whenever this host has not - built that LLVM. CMake is in `REQUIRED` because every build keys the host's - LLVM on `cmake --version` (`src/llvm.rs`); Ninja is in `ALSO_USED` because a - build whose LLVM is already built does not run it. No Rust tool does the job: - LLVM, clang and LLD are described in CMake, and the only other descriptions - upstream carries are an unsupported GN overlay (`BUILD.gn`) and a Bazel one. - -**Also run, and declared here:** - -- **`git`** — `REQUIRED`: every build, and the image ships what git says is - tracked. -- **`gh`** — Go, so outside the rule. `src/release.rs` asks GitHub whether a - toolchain release exists, creates it and moves the `sdk-` alias with - it, on a runner only. Exit: `src/release.rs` speaks GitHub's REST API itself. -- **`xcrun`** — macOS's, so outside the rule. On macOS `src/llvm.rs` asks it for - the SDK's path and version, which the LLVM's key names. Exit: the key names - the SDK without asking `xcrun`. -- **`curl`**, and **`ca-certificates`**, the trust store it verifies against — - `src/release.rs` downloads the toolchain release, `src/sdkversion.rs` asks - the crates.io index, and the nightly's container and macOS jobs fetch - `rustup-init.sh` with it. Exit: those fetches are Rust's, and a job - installs rustup without it. -- **`tar`** and **`zstd`** — `src/release.rs` packs and unpacks the toolchain - release. Exit: both are done in Rust, in-process. -- **`ssh`** — `src/metal.rs` reaches the T14's Ubuntu with it, only when the - metal loop is asked for. Exit: that loop drives the repository's own russh - client, `crate::build::ssh_client_host`, which `src/metaltalk.rs` already - drives at a booted T14. -- **`ovmf-generic`** — the guest container's UEFI firmware - (`src/firmware.rs`), which Debian packages apart from QEMU. Exit: the - instrument's QEMU carries its own firmware. -- **`build-essential`** — Debian's package for `cc` and `c++`, which the - nightly's guest containers and `portability-linux` install: every host - binary those jobs build links through `cc`, `ring`'s C compiles with it, and - `portability-linux` builds LLVM with `c++`. Exit: it goes with `cc`. +| tool | runs | verdict | exit | +|---|---|---|---| +| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`) | M5 runs it in the guest | +| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | +| Ninja | runs the build CMake generates for LLVM | admitted: no Rust tool does the job, bootstrap has CMake generate for Ninja, and no CMake generator targets a Rust tool | M5 runs it in the guest | +| `git` | every build, which also adds worktrees (`src/worktree.rs`) and updates submodules (`src/lib.rs`, `src/sysroot.rs`); rustc's bootstrap; every workflow's checkout | admitted: no Rust tool does the job, gitoxide 0.85 adds no worktree and updates no submodule | M4 runs it in the guest | +| `cc`, `c++` and `ar` on a Linux host, `build-essential` on the nightly's runners | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap) and `ring`'s C for `tests/https-server-host` and `tests/https-fetch-host`; `ar` archives what `cc::Build` compiles | admitted: no Rust tool compiles C or C++, or takes rustc's host link | M5: no host in the loop | +| `ovmf-generic` | the UEFI firmware of the nightly's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | +| `ca-certificates` | the trust store `git` and `curl` verify against in the nightly's containers | admitted: data both of them need | goes when neither runs there | +| `env` | the two portability jobs run `cargo run -- --build-only` under it, with `GITHUB_ACTIONS` and `CI` unset | admitted: no Rust tool on the runner unsets a variable for one command | M5: no host in the loop | +| `sudo`, `dd`, `wipefs`, `efibootmgr`, `udevadm`, `mount`, `umount`, `reboot`, `visudo`, `install`, `systemd-analyze`, `ip`, `date`, `cat`, `ls`, `test`, `mkdir`, `rm`, `true`, and the login shell each command reaches | `src/metal.rs`, over `ssh`, on the T14's Ubuntu and never on a development host | admitted: no Rust tool does their job on that Ubuntu | Ubuntu leaves the metal loop (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | +| `sh` running `rust/x`, and Python running `x.py` and `bootstrap.py` | every toolchain build (`src/toolchain.rs`) | refused: a Rust tool does it, upstream's bootstrap binary, which builds with stable cargo, fetches its own stage0 (`rust/src/bootstrap/src/core/download.rs:595`) and needs no Python | `src/toolchain.rs` runs the bootstrap binary | +| `curl` in rustc's bootstrap | fetches the stage0 `rust/src/stage0` pins, for a compiler or LLVM build whose build directory lacks it, whichever bootstrap runs | refused: a Rust tool does it, rustup installs the dated beta the pin names, and bootstrap takes a stage0 through `build.rustc` and `build.cargo`, as `src/sysroot.rs` hands it one | no toolchain build fetches with `curl` | +| `curl` in `src/release.rs` and `src/sdkversion.rs` | the toolchain release's lookup and download and the crates.io index, on CI runners only | refused: a Rust tool does it, `ureq`, which `userland/doom/build.rs` already fetches with | those fetches are Rust's | +| `tar` and `zstd` | `src/release.rs` packs and unpacks the toolchain release, on CI runners only | refused: a Rust tool does it, the `tar` crate `userland/doom/build.rs` already unpacks with, and a zstd crate | both are done in Rust, in-process | +| `gh` | `src/release.rs` asks whether a toolchain release exists, creates it and moves the `sdk-` alias, on the nightly's `build` runner | refused: not C or C++ source, it is Go | `src/release.rs` speaks GitHub's REST API itself | +| `ssh` | `src/metal.rs` reaches the T14's Ubuntu with it, only in the metal loop | refused: a Rust tool does it, the repository's own russh client `crate::build::ssh_client_host`, which `src/metaltalk.rs` already drives | `src/metal.rs` drives that client, or Ubuntu leaves the loop | +| `cc`, `c++`, `ar` and `xcrun` on a macOS host, Apple's Command Line Tools | what the Linux row's tools do, and rustc asks `xcrun` for the SDK on every host link that names no `SDKROOT` (`rust/compiler/rustc_codegen_ssa/src/back/apple.rs:230`), as `src/llvm.rs` does for the LLVM's key | refused: one host OS alone | M5: no host in the loop | +| `newfs_msdos` and `hdiutil` | `toyos-fat32`'s host tests format and mount their fixtures with them (`toyos-fat32/tests/common/mod.rs`), which keeps the `host` job on `macos-latest` | refused: one host OS alone | `issues/filesystem/fat32-suite-needs-macos-binaries.md` | +| `diag/flash.sh` | the owner's flash of a stick by hand: `bash`, and the `stat`, `seq`, `tr`, `grep`, `cut` and `sync` it strings together | refused: shell of our own | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `diskutil` and `plutil` | `diag/flash.sh`, and `diskutil` in the README's flashing steps | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `shasum`, a Perl script on macOS | `diag/flash.sh` hashes the image with it | refused: a Rust tool does it, `sha2`, which `src/release.rs` hashes with | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `dd` | `diag/flash.sh` writes the stick with it | refused: a Rust tool does it, the build system can write the image itself | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `sudo` | `diag/flash.sh` runs `dd` under it | admitted: no Rust tool raises a process to root on macOS | goes with `diag/flash.sh` | +| `sh` running rustup's `rustup-init.sh` | the nightly's three rustup installs, fetched with `curl` | refused: a Rust tool does it, rustup's own `rustup-init` binary | a job installs rustup without it | +| `nightly.yml`, job `build`, step "disk, QEMU, CMake and Ninja" | `sudo rm -rf` of five preinstalled SDK directories, then `sudo apt-get update` and `install` | refused: shell of our own | each step is one command | +| `nightly.yml`, step `deps`, which jobs `guest` and `tcg` share | the snapshot archive read out of `debian.sources` with `sed`, checked with `test` and written back with `echo` and `rm`, a three-attempt `apt-get` loop with `sleep` and `cat`, `git config`, and rustup through `curl`, `sh` and `echo` | refused: shell of our own | each step is one command | +| `nightly.yml`, job `portability-linux`, step "deps" | the same loop, `git config`, and rustup the same way | refused: shell of our own | each step is one command | +| `nightly.yml`, job `portability-macos`, the rustup step | `curl`, `sh rustup-init.sh`, and `echo` into `$GITHUB_PATH` | refused: shell of our own | each step is one command | +| `umask 077 && cat > ` | `src/metal.rs` stages the sudoers rule on the T14 with it | refused: shell of our own | Ubuntu leaves the metal loop | diff --git a/issues/build/the-owners-flash-script-runs-diskutil.md b/issues/build/the-owners-flash-script-runs-diskutil.md index 4284418f1c3..f01fd1ac2b8 100644 --- a/issues/build/the-owners-flash-script-runs-diskutil.md +++ b/issues/build/the-owners-flash-script-runs-diskutil.md @@ -4,7 +4,7 @@ kind: tooling opened: 2026-09-29 --- -# The owner's flash script runs `diskutil`, and no ledger declares it +# The owner's flash script runs `diskutil` `diag/flash.sh` writes an image to a USB stick through `diskutil` and `plutil`, which are macOS binaries, and through `shasum`, `dd` and `sudo`. The README's diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index 96df8041b44..cb7fabf9894 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -35,8 +35,9 @@ AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track. bytes equal the host's. *Exit*: a guest build of the image whose hashes match the host build of the same commit. - **M5 — ToyOS rebuilds its own compilers to a fixed point; the host is no - longer needed.** The guest's toolchain builds the next toolchain, and that - one builds itself again to the same bytes. + longer needed.** The guest's toolchain builds the next toolchain, its LLVM + with Python, CMake and Ninja built for ToyOS, and that one builds itself + again to the same bytes. *Exit*: the fixed point, reached with no host in the loop. **Blocked on other tracks.** M2 needs packages over HTTPS diff --git a/issues/filesystem/fat32-suite-needs-macos-binaries.md b/issues/filesystem/fat32-suite-needs-macos-binaries.md index e5aae9c72d2..0606aefe00a 100644 --- a/issues/filesystem/fat32-suite-needs-macos-binaries.md +++ b/issues/filesystem/fat32-suite-needs-macos-binaries.md @@ -9,9 +9,7 @@ opened: 2026-08-08 **The judge is ours as of 2026-08-08.** `fsck_msdos` is gone from all three places it was used — `src/image.rs`, `tests/common/volumes.rs` and `toyos-fat32/tests/common/mod.rs` — replaced by `toyos-fat32-check/`, written -from fatgen103 and derived from neither our writer nor our reader. The owner's -rule that made that mandatory: "no dependencies on binaries that dont come with -rust or qemu". The stale FAT mirror and duplicate 8.3 names, both of which +from fatgen103 and derived from neither our writer nor our reader. The stale FAT mirror and duplicate 8.3 names, both of which `fsck_msdos` silently accepted, are among the twelve corruptions the new checker catches and it did not. From ae253b805a81f3256ed6aa7015b698bc636e8f4c Mon Sep 17 00:00:00 2001 From: japabu Date: Tue, 29 Sep 2026 23:17:06 +0200 Subject: [PATCH 5/7] The north star's clause comes back as the owner wrote it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "nothing — build, test, or verification — rests on a host binary. Self-hosting means" is restored to CLAUDE.md's Dependencies exactly as main has it. It is the owner's own text, and it says tests and verification too, which the rest of the sentence does not. Nothing else is cut in its place. CLAUDE.md is 2628 words (`wc -w`) against main's 2614. The 14 words are the owner's ruling's growth: line 61 goes from 192 to 214 words and line 65 from 48 to 40. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index f1837763852..d36ebcb1e7c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,7 +58,7 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. No Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. No Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. From 9ef3867e6742c4bc447aa2dccc2ef48fb155115b Mon Sep 17 00:00:00 2001 From: japabu Date: Wed, 30 Sep 2026 14:06:53 +0200 Subject: [PATCH 6/7] Answer the second review of #632: Ninja measured against n2, git judged per use The declaration is renamed to what its rows are, host tools and not only C and C++ ones: issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md. Its one citation, reviewer.md's Arrivals, moves in this commit. BLOCKERs: - env is refused. src/release.rs already runs `cargo run -- --build-only` with GITHUB_ACTIONS and CI removed, so a Rust tool does the job. Exit: the build system removes both itself. - Ninja is refused: n2 does its job. n2 is github.com/evmar/n2 at b1fead5, built from source in a scratch directory (the crates.io `n2` is an unrelated crate). LLVM was configured from the primary's rust/src/llvm-project/llvm at 52ed14fcd56a, the upstream commit the pin a79bc52c1d5e adds five ToyOS commits to, none of them in llvm/CMakeLists.txt, llvm/cmake, lib/Support, lib/TableGen or utils/TableGen. Flags: Release, X86 only, no tests, benchmarks, examples or docs. - `cmake -G Ninja -DCMAKE_MAKE_PROGRAM=`: exit 1, "The detected version of Ninja (0.1.0) is less than the version of Ninja required by CMake (1.3)". - The same with CMAKE_MAKE_PROGRAM a symlink named `ninja` to n2, which is how n2's README says CMake runs it: configure exit 0; `n2 -C build -j 8 llvm-tblgen` exit 0, "n2: ran 304 tasks, now up to date"; the same again and `cmake --build build --target llvm-tblgen` exit 0, "n2: no work to do"; `bin/llvm-tblgen --version` exit 0, "LLVM version 22.1.8". The build directory holds .n2_db and no .ninja_log. - The same again with n2 built --no-default-features, which drops its jemalloc so that no C is linked into it: every step exit 0, 304 tasks. `find` over the primary's llvm-project for files newer than a marker touched before each arm printed nothing. The scratch builds are deleted. M5 in issues/build/toyos-builds-itself.md no longer builds Ninja for ToyOS. - The T14 bench is outside the rule. The orchestrator read the bench's release, "Ubuntu 24.04.4 LTS", with sudo 1.9.15p5 and dd (coreutils) 9.4, both C, and ruled its Ubuntu recovery equipment on a test machine, not the build's host. One row says so with that release, and its tools leave with Ubuntu. NOTEs: - The toolchain's own clang, llvm-ar, rust-lld and llvm-config, built from ToyOSOrg/llvm-project, are an admitted row: rustc links every guest binary with rust-lld, the C corpus, hello.c and doomgeneric compile with clang, cc::Build archives with llvm-ar, and bootstrap reads LLVM through llvm-config. - reviewer.md's Arrivals names a `.github/` `run:` step, which is how env, sed, sleep and the build job's `sudo rm -rf` arrive. The declaration's intro no longer claims every row was found by those ways: it names the two flashes by hand as its own scope. - git is two rows, split by what gitoxide 0.85 does, read in its source in ~/.cargo/registry. Admitted: adding, removing and pruning worktrees, updating submodules, the fork's fetch from the primary's and its checkout, the primary's fast-forward, the tests' fixture repositories, and rustc's bootstrap. gix 0.85 has worktrees() and no worktree add; Submodule::update reads the config's setting and updates nothing; there is no checkout of an existing worktree, no reset, no push and no staging (gix-index's add_entry builds an index from a tree); and gix-transport 0.57.2's local connect "will spawn a `git` process locally". Refused: every read (rev-parse, show-ref, for-each-ref, rev-list, log, branch --contains, merge-base, ls-tree, ls-files, cat-file, config --get-regexp, worktree list, status, diff, ls-remote, grep), src/sync.rs's fetch of origin over HTTPS, and the workflows' checkouts: gix has rev_parse, merge_base, rev_walk, status, worktrees, has_object, index, submodules, diff_tree_to_tree, ref_map and clone, and reqwest for HTTPS. - The README's flashing steps: lsblk, sync and sudo on Linux have rows, and the dd and macOS sudo rows name the README's steps. - CLAUDE.md carries the ruling's "ToyOS's own code is Rust; it writes no Python, Perl or shell of its own." in place of its paraphrase, and main's "Ask of anything new: could this ever run inside ToyOS?" where it was, both word for word. `wc -w CLAUDE.md`: 2614 on main, 2645 here. - reviewer.md's Instructions carve-out reaches CLAUDE.md's "Stale or false prose is deleted" and "an agent edits one only when briefed to" for the implementer updating an instruction. - Filed issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md: sysroot::fork_checkout runs `git submodule update --init library/backtrace` in a linked worktree of the primary's rust whenever the primary's backtrace lacks the pinned commit, which implementer.md forbids. REMOVEs: the fork line numbers after download.rs and apple.rs are deleted, and the pull request body no longer describes #631. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L --- .claude/agents/reviewer.md | 15 ++++++---- CLAUDE.md | 2 +- ...-runs-host-tools-outside-rust-and-qemu.md} | 29 +++++++++++-------- ...runs-git-submodule-in-a-linked-worktree.md | 20 +++++++++++++ issues/build/toyos-builds-itself.md | 2 +- 5 files changed, 48 insertions(+), 20 deletions(-) rename issues/build/{the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md => the-build-runs-host-tools-outside-rust-and-qemu.md} (57%) create mode 100644 issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index 050c71e05e8..454b05243ba 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -53,13 +53,16 @@ above; otherwise it is a NOTE. - **Instructions.** A change that removes or renames a command, flag or step an agent runs updates every prompt that names it — each `CLAUDE.md` and `.claude/agents/*.md` — in the same diff, saying what to do instead. Such an instruction is not the prose "Prose is removed, never - reviewed" governs: one left naming what is gone is a BLOCKER. + reviewed" governs, and `CLAUDE.md`'s "Stale or false prose is deleted" and "an agent edits one + only when briefed to" do not bar the implementer updating it: one left naming what is gone is a + BLOCKER. - **Arrivals.** A host tool outside Rust and QEMU arrives by `Command::new`, `libc::system`, - `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` package manager or `sh -c`, - and is declared in `issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md` and - nowhere else. A BLOCKER each: an undeclared host tool; one, like Go's `gh`, not built from C or - C++ source ToyOS can one day build and run; a binary for one host OS alone; a C or C++ tool - taken where a Rust tool does the job; new Python, Perl or shell of ToyOS's own. + `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` `run:` step or package + manager, or `sh -c`, and is declared in + `issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md` and nowhere else. A BLOCKER + each: an undeclared host tool; one, like Go's `gh`, not built from C or C++ source ToyOS can + one day build and run; a binary for one host OS alone; a C or C++ tool taken where a Rust tool + does the job; new Python, Perl or shell of ToyOS's own. A third-party action `main` does not use is refused, and every `uses:` pins a 40-hex commit with its tag in a trailing comment or names a local path that resolves. A file added to or deleted from `tests/testcases/tinycc/` moves the count diff --git a/CLAUDE.md b/CLAUDE.md index d36ebcb1e7c..9f970a016fc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,7 +58,7 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. No Python, Perl or shell of our own; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. ToyOS's own code is Rust; it writes no Python, Perl or shell of its own. Only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. diff --git a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md similarity index 57% rename from issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md rename to issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md index 3646f3ea2e2..07103145f6e 100644 --- a/issues/build/the-build-runs-c-and-cxx-tools-toyos-does-not-yet-run.md +++ b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -4,38 +4,43 @@ kind: tooling opened: 2026-09-29 --- -# The build runs C and C++ tools that ToyOS does not yet build and run +# The build runs host tools outside Rust and QEMU Every tool `main`'s build, tests, workflows and metal loop run outside Rust and -QEMU, found by the ways `.claude/agents/reviewer.md`'s Arrivals names, with the -verdict of `CLAUDE.md`'s Dependencies on each; a refused row is a standing -failure. A workflow's package manager, `apt-get` or `brew`, is how a row +QEMU, and every one `diag/flash.sh` and the README's flashing steps run by hand, +with the verdict of `CLAUDE.md`'s Dependencies on each; a refused row is a +standing failure. A workflow's package manager, `apt-get` or `brew`, is how a row arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itself.md`. | tool | runs | verdict | exit | |---|---|---|---| | Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`) | M5 runs it in the guest | | CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | -| Ninja | runs the build CMake generates for LLVM | admitted: no Rust tool does the job, bootstrap has CMake generate for Ninja, and no CMake generator targets a Rust tool | M5 runs it in the guest | -| `git` | every build, which also adds worktrees (`src/worktree.rs`) and updates submodules (`src/lib.rs`, `src/sysroot.rs`); rustc's bootstrap; every workflow's checkout | admitted: no Rust tool does the job, gitoxide 0.85 adds no worktree and updates no submodule | M4 runs it in the guest | +| Ninja | runs the build CMake generates for LLVM | refused: a Rust tool does it, n2, named `ninja` as its README directs for CMake: CMake's Ninja generator configured `rust/src/llvm-project/llvm` for it and it built `llvm-tblgen`, exit 0 each; named `n2`, CMake refuses its version, exit 1 | rustc's bootstrap builds LLVM under n2 | +| `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds, removes and prunes worktrees (`src/worktree.rs`, `src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`, `src/licence.rs`, `src/release.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); fast-forwards the primary (`src/sync.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, merges, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | +| `git` for reads, and for clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names | those are gitoxide's | | `cc`, `c++` and `ar` on a Linux host, `build-essential` on the nightly's runners | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap) and `ring`'s C for `tests/https-server-host` and `tests/https-fetch-host`; `ar` archives what `cc::Build` compiles | admitted: no Rust tool compiles C or C++, or takes rustc's host link | M5: no host in the loop | +| the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus and `hello.c` (`tests/common/compile.rs`, `tests/common/clang.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | | `ovmf-generic` | the UEFI firmware of the nightly's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | | `ca-certificates` | the trust store `git` and `curl` verify against in the nightly's containers | admitted: data both of them need | goes when neither runs there | -| `env` | the two portability jobs run `cargo run -- --build-only` under it, with `GITHUB_ACTIONS` and `CI` unset | admitted: no Rust tool on the runner unsets a variable for one command | M5: no host in the loop | -| `sudo`, `dd`, `wipefs`, `efibootmgr`, `udevadm`, `mount`, `umount`, `reboot`, `visudo`, `install`, `systemd-analyze`, `ip`, `date`, `cat`, `ls`, `test`, `mkdir`, `rm`, `true`, and the login shell each command reaches | `src/metal.rs`, over `ssh`, on the T14's Ubuntu and never on a development host | admitted: no Rust tool does their job on that Ubuntu | Ubuntu leaves the metal loop (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | -| `sh` running `rust/x`, and Python running `x.py` and `bootstrap.py` | every toolchain build (`src/toolchain.rs`) | refused: a Rust tool does it, upstream's bootstrap binary, which builds with stable cargo, fetches its own stage0 (`rust/src/bootstrap/src/core/download.rs:595`) and needs no Python | `src/toolchain.rs` runs the bootstrap binary | +| `env` | the two portability jobs run `cargo run -- --build-only` under it, with `GITHUB_ACTIONS` and `CI` unset | refused: a Rust tool does it, the build system, which already runs that build with both removed (`src/release.rs`) | the build system removes both itself | +| the T14's Ubuntu, 24.04.4 LTS, and every tool `src/metal.rs` runs on it over `ssh` | the metal loop, on the T14 and never on a development host | outside the rule: recovery equipment on a test machine, not the build's host | they leave with Ubuntu (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | +| `sh` running `rust/x`, and Python running `x.py` and `bootstrap.py` | every toolchain build (`src/toolchain.rs`) | refused: a Rust tool does it, upstream's bootstrap binary, which builds with stable cargo, fetches its own stage0 (`rust/src/bootstrap/src/core/download.rs`) and needs no Python | `src/toolchain.rs` runs the bootstrap binary | | `curl` in rustc's bootstrap | fetches the stage0 `rust/src/stage0` pins, for a compiler or LLVM build whose build directory lacks it, whichever bootstrap runs | refused: a Rust tool does it, rustup installs the dated beta the pin names, and bootstrap takes a stage0 through `build.rustc` and `build.cargo`, as `src/sysroot.rs` hands it one | no toolchain build fetches with `curl` | | `curl` in `src/release.rs` and `src/sdkversion.rs` | the toolchain release's lookup and download and the crates.io index, on CI runners only | refused: a Rust tool does it, `ureq`, which `userland/doom/build.rs` already fetches with | those fetches are Rust's | | `tar` and `zstd` | `src/release.rs` packs and unpacks the toolchain release, on CI runners only | refused: a Rust tool does it, the `tar` crate `userland/doom/build.rs` already unpacks with, and a zstd crate | both are done in Rust, in-process | | `gh` | `src/release.rs` asks whether a toolchain release exists, creates it and moves the `sdk-` alias, on the nightly's `build` runner | refused: not C or C++ source, it is Go | `src/release.rs` speaks GitHub's REST API itself | | `ssh` | `src/metal.rs` reaches the T14's Ubuntu with it, only in the metal loop | refused: a Rust tool does it, the repository's own russh client `crate::build::ssh_client_host`, which `src/metaltalk.rs` already drives | `src/metal.rs` drives that client, or Ubuntu leaves the loop | -| `cc`, `c++`, `ar` and `xcrun` on a macOS host, Apple's Command Line Tools | what the Linux row's tools do, and rustc asks `xcrun` for the SDK on every host link that names no `SDKROOT` (`rust/compiler/rustc_codegen_ssa/src/back/apple.rs:230`), as `src/llvm.rs` does for the LLVM's key | refused: one host OS alone | M5: no host in the loop | +| `cc`, `c++`, `ar` and `xcrun` on a macOS host, Apple's Command Line Tools | what the Linux row's tools do, and rustc asks `xcrun` for the SDK on every host link that names no `SDKROOT` (`rust/compiler/rustc_codegen_ssa/src/back/apple.rs`), as `src/llvm.rs` does for the LLVM's key | refused: one host OS alone | M5: no host in the loop | | `newfs_msdos` and `hdiutil` | `toyos-fat32`'s host tests format and mount their fixtures with them (`toyos-fat32/tests/common/mod.rs`), which keeps the `host` job on `macos-latest` | refused: one host OS alone | `issues/filesystem/fat32-suite-needs-macos-binaries.md` | | `diag/flash.sh` | the owner's flash of a stick by hand: `bash`, and the `stat`, `seq`, `tr`, `grep`, `cut` and `sync` it strings together | refused: shell of our own | `issues/build/the-owners-flash-script-runs-diskutil.md` | | `diskutil` and `plutil` | `diag/flash.sh`, and `diskutil` in the README's flashing steps | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | | `shasum`, a Perl script on macOS | `diag/flash.sh` hashes the image with it | refused: a Rust tool does it, `sha2`, which `src/release.rs` hashes with | `issues/build/the-owners-flash-script-runs-diskutil.md` | -| `dd` | `diag/flash.sh` writes the stick with it | refused: a Rust tool does it, the build system can write the image itself | `issues/build/the-owners-flash-script-runs-diskutil.md` | -| `sudo` | `diag/flash.sh` runs `dd` under it | admitted: no Rust tool raises a process to root on macOS | goes with `diag/flash.sh` | +| `lsblk` | the README's Linux flashing steps find the stick with it | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `dd` | `diag/flash.sh` and the README's flashing steps write the stick with it | refused: a Rust tool does it, the build system can write the image itself | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `sync` | the README's Linux flashing steps flush the stick with it | refused: a Rust tool does it, the build system can flush what it writes | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `sudo` on macOS | `diag/flash.sh` and the README's macOS flashing steps run `dd` under it | admitted: no Rust tool raises a process to root on macOS | goes with both flashes by hand | +| `sudo` on Linux | the README's Linux flashing steps run `dd` under it | refused: a Rust tool does it, sudo-rs | the README's Linux steps run sudo-rs | | `sh` running rustup's `rustup-init.sh` | the nightly's three rustup installs, fetched with `curl` | refused: a Rust tool does it, rustup's own `rustup-init` binary | a job installs rustup without it | | `nightly.yml`, job `build`, step "disk, QEMU, CMake and Ninja" | `sudo rm -rf` of five preinstalled SDK directories, then `sudo apt-get update` and `install` | refused: shell of our own | each step is one command | | `nightly.yml`, step `deps`, which jobs `guest` and `tcg` share | the snapshot archive read out of `debian.sources` with `sed`, checked with `test` and written back with `echo` and `rm`, a three-attempt `apt-get` loop with `sleep` and `cat`, `git config`, and rustup through `curl`, `sh` and `echo` | refused: shell of our own | each step is one command | diff --git a/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md new file mode 100644 index 00000000000..3949e6908b9 --- /dev/null +++ b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md @@ -0,0 +1,20 @@ +--- +status: open +kind: tooling +opened: 2026-09-30 +--- + +# The fork checkout runs `git submodule` in a linked worktree + +`sysroot::fork_checkout` makes a worktree's `rust/` a linked worktree of the +primary's `rust` (`git worktree add --detach`). When the primary's +`library/backtrace` lacks the commit the fork pins, it runs +`git submodule update --init library/backtrace` inside that linked worktree, +which `.claude/agents/implementer.md` forbids: `git submodule` in a linked +worktree writes `core.worktree` into shared config and breaks git in the +primary checkout's `rust/`. The orchestrator measured that for +`git submodule update rust` in a linked worktree of the monorepo, which set the +primary's `.git/modules/rust/config` `core.worktree` to a path that does not +exist; this arm is the same command one level down and is unmeasured. + +**Exit**: `fork_checkout` runs no `git submodule` in a linked worktree. diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index cb7fabf9894..06e3fd75fa6 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -36,7 +36,7 @@ AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track. the host build of the same commit. - **M5 — ToyOS rebuilds its own compilers to a fixed point; the host is no longer needed.** The guest's toolchain builds the next toolchain, its LLVM - with Python, CMake and Ninja built for ToyOS, and that one builds itself + with Python and CMake built for ToyOS, and that one builds itself again to the same bytes. *Exit*: the fixed point, reached with no host in the loop. From e9262d7a6f3e97c08860d5a05067fb70efbb96bd Mon Sep 17 00:00:00 2001 From: japabu Date: Wed, 30 Sep 2026 15:53:49 +0200 Subject: [PATCH 7/7] Answer the third review of #632: every exit names what it covers - The fork-checkout issue reaches `ensure_submodule`, which runs `git submodule update --init library/backtrace` in the same linked-worktree fork from `sysroot::build_std` and `compiler::build_in_fork` whenever its `library/backtrace` is empty or gone. Its exit is now the build system's, not `fork_checkout`'s alone. - The flash issue names the README's `dd` under `sudo`, and `lsblk` and `sync` on Linux, and its exit requires the README's flashing steps to run none of `lsblk`, `dd` or `sync`. The steps stay: `target/bootable.img` is the build's default image. - `git config --global --add safe.directory` (nightly.yml) is in the refused git row: gix-config 0.58, which gix 0.85 depends on, adds a value to a section (`File::section_mut_or_create_new`, `SectionMut::push`) and writes the file (`File::write_to`), read in its source in ~/.cargo/registry. - n2 is named as `github.com/evmar/n2` at `b1fead5`; the crates.io `n2` is an unrelated neural-network crate. - macOS `sudo` stays admitted: sudo-rs's README at 89bae8a says it "is targeted for FreeBSD and Linux-based operating systems only". - reviewer.md's Instructions carve-out also reaches CLAUDE.md's "a `CLAUDE.md` never grows". - Deleted: "merges," from the admitted git row (gix 0.85 has `Repository::merge_trees` and `merge_commits`), the T14's Ubuntu point release, and src/main.rs's "They go when the build no longer needs a host.", false against the declaration's CMake and Ninja exits. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L --- .claude/agents/reviewer.md | 6 +++--- .../the-build-runs-host-tools-outside-rust-and-qemu.md | 10 +++++----- ...checkout-runs-git-submodule-in-a-linked-worktree.md | 9 ++++++++- issues/build/the-owners-flash-script-runs-diskutil.md | 8 +++++--- src/main.rs | 2 +- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index 454b05243ba..c780b0dee34 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -53,9 +53,9 @@ above; otherwise it is a NOTE. - **Instructions.** A change that removes or renames a command, flag or step an agent runs updates every prompt that names it — each `CLAUDE.md` and `.claude/agents/*.md` — in the same diff, saying what to do instead. Such an instruction is not the prose "Prose is removed, never - reviewed" governs, and `CLAUDE.md`'s "Stale or false prose is deleted" and "an agent edits one - only when briefed to" do not bar the implementer updating it: one left naming what is gone is a - BLOCKER. + reviewed" governs, and `CLAUDE.md`'s "Stale or false prose is deleted", "an agent edits one + only when briefed to" and "a `CLAUDE.md` never grows" do not bar the implementer updating it: + one left naming what is gone is a BLOCKER. - **Arrivals.** A host tool outside Rust and QEMU arrives by `Command::new`, `libc::system`, `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` `run:` step or package manager, or `sh -c`, and is declared in diff --git a/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md index 07103145f6e..77ff0585707 100644 --- a/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md +++ b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -16,15 +16,15 @@ arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itsel |---|---|---|---| | Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`) | M5 runs it in the guest | | CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | -| Ninja | runs the build CMake generates for LLVM | refused: a Rust tool does it, n2, named `ninja` as its README directs for CMake: CMake's Ninja generator configured `rust/src/llvm-project/llvm` for it and it built `llvm-tblgen`, exit 0 each; named `n2`, CMake refuses its version, exit 1 | rustc's bootstrap builds LLVM under n2 | -| `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds, removes and prunes worktrees (`src/worktree.rs`, `src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`, `src/licence.rs`, `src/release.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); fast-forwards the primary (`src/sync.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, merges, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | -| `git` for reads, and for clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names | those are gitoxide's | +| Ninja | runs the build CMake generates for LLVM | refused: a Rust tool does it, n2 (`github.com/evmar/n2` at `b1fead5`), named `ninja` as its README directs for CMake: CMake's Ninja generator configured `rust/src/llvm-project/llvm` for it and it built `llvm-tblgen`, exit 0 each; named `n2`, CMake refuses its version, exit 1 | rustc's bootstrap builds LLVM under n2 | +| `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds, removes and prunes worktrees (`src/worktree.rs`, `src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`, `src/licence.rs`, `src/release.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); fast-forwards the primary (`src/sync.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | +| `git` for reads, a config write, and clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in the nightly's containers; `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names | those are gitoxide's | | `cc`, `c++` and `ar` on a Linux host, `build-essential` on the nightly's runners | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap) and `ring`'s C for `tests/https-server-host` and `tests/https-fetch-host`; `ar` archives what `cc::Build` compiles | admitted: no Rust tool compiles C or C++, or takes rustc's host link | M5: no host in the loop | | the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus and `hello.c` (`tests/common/compile.rs`, `tests/common/clang.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | | `ovmf-generic` | the UEFI firmware of the nightly's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | | `ca-certificates` | the trust store `git` and `curl` verify against in the nightly's containers | admitted: data both of them need | goes when neither runs there | | `env` | the two portability jobs run `cargo run -- --build-only` under it, with `GITHUB_ACTIONS` and `CI` unset | refused: a Rust tool does it, the build system, which already runs that build with both removed (`src/release.rs`) | the build system removes both itself | -| the T14's Ubuntu, 24.04.4 LTS, and every tool `src/metal.rs` runs on it over `ssh` | the metal loop, on the T14 and never on a development host | outside the rule: recovery equipment on a test machine, not the build's host | they leave with Ubuntu (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | +| the T14's Ubuntu and every tool `src/metal.rs` runs on it over `ssh` | the metal loop, on the T14 and never on a development host | outside the rule: recovery equipment on a test machine, not the build's host | they leave with Ubuntu (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | | `sh` running `rust/x`, and Python running `x.py` and `bootstrap.py` | every toolchain build (`src/toolchain.rs`) | refused: a Rust tool does it, upstream's bootstrap binary, which builds with stable cargo, fetches its own stage0 (`rust/src/bootstrap/src/core/download.rs`) and needs no Python | `src/toolchain.rs` runs the bootstrap binary | | `curl` in rustc's bootstrap | fetches the stage0 `rust/src/stage0` pins, for a compiler or LLVM build whose build directory lacks it, whichever bootstrap runs | refused: a Rust tool does it, rustup installs the dated beta the pin names, and bootstrap takes a stage0 through `build.rustc` and `build.cargo`, as `src/sysroot.rs` hands it one | no toolchain build fetches with `curl` | | `curl` in `src/release.rs` and `src/sdkversion.rs` | the toolchain release's lookup and download and the crates.io index, on CI runners only | refused: a Rust tool does it, `ureq`, which `userland/doom/build.rs` already fetches with | those fetches are Rust's | @@ -39,7 +39,7 @@ arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itsel | `lsblk` | the README's Linux flashing steps find the stick with it | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | | `dd` | `diag/flash.sh` and the README's flashing steps write the stick with it | refused: a Rust tool does it, the build system can write the image itself | `issues/build/the-owners-flash-script-runs-diskutil.md` | | `sync` | the README's Linux flashing steps flush the stick with it | refused: a Rust tool does it, the build system can flush what it writes | `issues/build/the-owners-flash-script-runs-diskutil.md` | -| `sudo` on macOS | `diag/flash.sh` and the README's macOS flashing steps run `dd` under it | admitted: no Rust tool raises a process to root on macOS | goes with both flashes by hand | +| `sudo` on macOS | `diag/flash.sh` and the README's macOS flashing steps run `dd` under it | admitted: no Rust tool raises a process to root on macOS; sudo-rs "is targeted for FreeBSD and Linux-based operating systems only" (its README at `89bae8a`) | goes with both flashes by hand | | `sudo` on Linux | the README's Linux flashing steps run `dd` under it | refused: a Rust tool does it, sudo-rs | the README's Linux steps run sudo-rs | | `sh` running rustup's `rustup-init.sh` | the nightly's three rustup installs, fetched with `curl` | refused: a Rust tool does it, rustup's own `rustup-init` binary | a job installs rustup without it | | `nightly.yml`, job `build`, step "disk, QEMU, CMake and Ninja" | `sudo rm -rf` of five preinstalled SDK directories, then `sudo apt-get update` and `install` | refused: shell of our own | each step is one command | diff --git a/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md index 3949e6908b9..96b22d6b0f2 100644 --- a/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md +++ b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md @@ -17,4 +17,11 @@ primary checkout's `rust/`. The orchestrator measured that for primary's `.git/modules/rust/config` `core.worktree` to a path that does not exist; this arm is the same command one level down and is unmeasured. -**Exit**: `fork_checkout` runs no `git submodule` in a linked worktree. +`ensure_submodule` (`src/lib.rs`) runs `git submodule update --init +library/backtrace` in the same fork checkout, from `sysroot::build_std` and +`compiler::build_in_fork`, whenever that checkout's `library/backtrace` is +empty or gone: what a first `fork_checkout` leaves when it stops after adding +the fork's worktree and before adding `library/backtrace`. + +**Exit**: the build system runs no `git submodule` in a linked worktree's fork +checkout. diff --git a/issues/build/the-owners-flash-script-runs-diskutil.md b/issues/build/the-owners-flash-script-runs-diskutil.md index f01fd1ac2b8..fbdefbdda12 100644 --- a/issues/build/the-owners-flash-script-runs-diskutil.md +++ b/issues/build/the-owners-flash-script-runs-diskutil.md @@ -8,7 +8,8 @@ opened: 2026-09-29 `diag/flash.sh` writes an image to a USB stick through `diskutil` and `plutil`, which are macOS binaries, and through `shasum`, `dd` and `sudo`. The README's -flashing steps also run `diskutil`. The metal loop does not use this script: it flashes +flashing steps also run `diskutil`, `dd` under `sudo` on both hosts, and `lsblk` +and `sync` on Linux. The metal loop does not use this script: it flashes the T14's stick over `ssh` from Ubuntu. The script's two gates are what keep it off an internal drive: it takes only @@ -16,5 +17,6 @@ disks that `diskutil list external physical` names, and it writes only to a disk that reports `Internal=false` and `BusProtocol=USB` on its own account. A replacement keeps both. -**Exit**: `rg -l "diskutil|plutil"` over the tree outside `rust/` finds nothing, and -the build system writes the stick. +**Exit**: `rg -l "diskutil|plutil"` over the tree outside `rust/` finds nothing, the +README's flashing steps run no `lsblk`, `dd` or `sync`, and the build system +writes the stick. diff --git a/src/main.rs b/src/main.rs index 8b1afe6d8a4..3ed298f68d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,7 @@ const REQUIRED: &[Tool] = &[ /// `rust/src/llvm-project` with, under CMake, which it does only when this /// host has not built that LLVM. Both are host tools like `cc`, and never in a /// guest: on macOS from Homebrew, on CI's toolchain runner at the versions -/// `.github/workflows` pins. They go when the build no longer needs a host. +/// `.github/workflows` pins. const ALSO_USED: &[Tool] = &[ Tool { any: &["python3", "python", "py", "python2", "uv"],