Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 5 additions & 35 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ An operating system built from scratch in Rust, held to a production-grade engin
There are no spec documents. Rules live where they are enforced — a gate, a
module header, the redlist, the review prompt — and everything else is an
issue. Free text that merely describes the tree rots and is deleted, not
maintained.
maintained. A `CLAUDE.md` never holds a list that a manifest, a directory or a
gate already answers; it points at that source instead.

A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not from `Bash`. A rule whose violation is unrecoverable or invisible stays here; everything else lives where the work is.

Expand All @@ -44,7 +45,7 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not

**Syscall ABI** — `toyos-abi/`: struct layouts, syscall numbers, typed wrappers; completely unstable, read the code. Never add or change a syscall without discussion; a deleted syscall's number is retired, never reused. `toyos/` builds on it with typed handles, IPC framing, ports, namespaces and `surface` — userland uses `toyos`, the kernel uses `toyos-abi` only.

**Capabilities** — a process holds exactly what its parent moved into it, and among kernel objects there is nothing it can name to get more. No registry, no connect-by-name, no pid-as-authority: `/system/bin/init` builds every program's namespace and device claims from `system.toml` before spawning it, and a handle a process does not hold is a bug in that process — the kernel ends it rather than answering a word it can ignore. **Isolation is non-negotiable, and the filesystem is inside it**: a process names only the paths in the view its parent built for it, the unit of isolation is the program, and a user is the part of the tree a session was handed.
**Capabilities** — a process holds exactly what its parent moved into it, and among kernel objects there is nothing it can name to get more. No registry, no connect-by-name, no pid-as-authority: `/system/bin/init` builds every program's namespace and device claims from `system.toml` before spawning it, and a handle a process does not hold is a bug in that process — the kernel ends it rather than answering a word it can ignore. **Isolation is non-negotiable, and the filesystem is inside it**: a process names only the paths in the view its parent built for it, the unit of isolation is the program, and a user is the part of the tree a session was handed. Not yet true of files: the kernel still resolves every path against one machine-wide tree until the storage track's per-program views land.

**CPU state** — a CPU's control registers come from one declaration, applied by the BSP and by every AP and asserted on each; no read-modify-write decides what either holds.

Expand All @@ -54,7 +55,7 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not

## Dependencies

Only **Rust** and **QEMU** (for development). 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.
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.

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.

Expand All @@ -74,38 +75,7 @@ The testing rules live where they are enforced: known reds in `src/redlist.rs`,

## Repository layout

```
src/ Build system (the root cargo project, package name: toyos-build; its Cargo.toml is also the host workspace, and a gate reds on a crate that joins neither members nor exclude)
kernel/ Kernel
kernel-loom/ Loom models of the kernel's lock-free concurrency, beside the kernel and not in it
toyos-userbound/ Every decision the kernel makes about the user/kernel boundary, pure
toyos-elide/ Log elision decisions, pure
toyos-proclife/ The process/thread lifecycle's decisions — pure, interleaving-checked
bootloader/ UEFI bootloader
userland/ All userland programs
toyos-abi/ Kernel ABI (types, constants, syscall numbers, syscall wrappers)
toyos/ Userland SDK (typed handles, IPC, ports, namespaces, surface, shm, net)
toyos-manifest/ The one definition of `/system/etc/system.manifest`
toyos-wallclock/ The calendar, and the zone offset userland has to recover — pure
toyos-keymap/ Layouts, dead-key composition, key translation, layout detection
toyos-fat32/ FAT32 driver, read + write; no format path by design
toyos-fat32-check/ FAT32 checker from Microsoft's fatgen103 — the outside judge
toyos-elf/ ELF64 decoding (no_std, no alloc, forbid(unsafe_code))
toyos-symbols/ Backtrace symbol lookup: locating an ELF's symbol tables and budgeting the demangled name (no_std, no alloc, forbid(unsafe_code))
toyos-gpt/ GPT parser (no_std, no alloc, forbid(unsafe_code))
toyos-hda/ HDA codec decoding and output-path selection, pure
toyos-mixer/ The mixer's decisions — samples, gain, dither, quantize — pure, corpus-certified
toyos-pci/ MSI and MSI-X capability decoding, pure
toyos-dma/ Every bound and alignment a DMA view checks — pure, forbid(unsafe_code)
toyos-blockhold/ Who holds each span of a block device, and whose flush answers for the writes its disk lost — pure
toyos-desktop/ Every decision the compositor makes, pure
toyos-ld/ Custom linker
toyos-cc/ Custom C compiler
rust/ Rust compiler/std fork (submodule)
tests/ Integration tests (QEMU-based)
issues/ The issue tracker: one file per issue, typed by kind — see its README
system.toml What to build and boot
```
The root `Cargo.toml`'s `[workspace]` `members` and `exclude` lists account for every crate in the tree, and `src/hostws.rs` reds on one in neither; every package they name says what it is in its `description`, and a gate there reds on one without.

## Workflow

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ exclude = [

[package]
name = "toyos-build"
description = "The build system: toolchain, kernel, bootloader, userland and image, the QEMU harness, CI jobs, and the gates the tree is held to."
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions bcachefs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[package]
name = "bcachefs"
description = "The /home filesystem: a read side of the real bcachefs on-disk format."
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions bootloader/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[package]
name = "bootloader"
description = "The UEFI bootloader, which loads the kernel and hands it the machine."
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion issues/audio/thorough-tier-reds-on-unmodified-main.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ the instrument refusing —
stopped' after the last client removal — the device is still running with no
clients`. That is filed apart as `gate-a-suspend-structure-verdict-unread`.

The exit code is fixed in `.github/workflows/gate-a.yml` (`set -o pipefail`, the
The exit code is fixed in `35383398^:.github/workflows/gate-a.yml` (`set -o pipefail`, the
idiom every other workflow in `.github/` already uses). Nothing about how a
verdict is *reached* changed.

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
---
status: open
kind: defect
kind: tooling
opened: 2026-09-26
---

# A lane's tap socket path outgrows `SUN_LEN` on the dev host

`lan_mdns_answer` reds wide and alone with `connect to QEMU's
/private/var/folders/gr/mr4_fg4n34jb417sx1g5cgxc0000gp/T/toyos-tmp-70685-0/tests-0/lane-7/tap-out-0.sock:
path must be shorter than SUN_LEN`. `common::segment::Tap::in_lane` puts the
two sockets in the lane's scratch directory, and on this macOS host that
directory sits under `$TMPDIR`, so the path is 104 bytes, past the 103 a
`sockaddr_un` holds before its terminating NUL on macOS.

Seen in the fast tier twice in one session: at `origin/main` checked out in
the `toyos-guiplat` worktree (alone with this message, wide as `QEMU died
before ===READY===`), and at PR #528's head after it merged `e48604c0` (this
message wide and alone). `cargo run
-- --known-red lan_mdns_answer` answers NO.

**Exit**: the socket paths fit a `sockaddr_un` wherever the scratch
directory is, with `lan_mdns_answer` green on this host.
`lan_mdns_answer` reds on the macOS dev host, wide and alone:

```
connect to QEMU's /private/var/folders/gr/mr4_fg4n34jb417sx1g5cgxc0000gp/T/toyos-tmp-89085-0/tests-0/lane-3/tap-out-0.sock: path must be shorter than SUN_LEN
```

That path is 104 bytes, past the 103 a `sockaddr_un` holds before its
terminating NUL on macOS. `tests/common/segment.rs`'s `Tap::in_lane` puts both
sockets in `lane::dir()`, which since `toyos-tmpdir` is
`$TMPDIR/toyos-tmp-<pid>-<n>/tests-<n>/lane-<i>/`, and the dev host's
`$TMPDIR` resolves to 57 bytes (`/private/var/folders/…/T/`) before any of
that. A five-digit pid is enough to cross the limit.

Seen three times on 2026-09-26, each on a tree whose diff touches neither the
lane nor the tap:

- on `wt/toyos-layout` after it merged `origin/main` at `e48604c0` (pid 89085,
`lane-3`, the capture above);
- in the fast tier at `origin/main` checked out in the `toyos-guiplat`
worktree: alone with this message, wide as `QEMU died before ===READY===`;
- in the fast tier at PR #528's head after it merged `e48604c0` (pid 70685,
`lane-7`), this message wide and alone.

`cargo run -- --known-red lan_mdns_answer` answers NO.

## Exit condition

A tap socket's path fits `sun_path` on every host the suite runs on, wherever
the scratch directory is, and `lan_mdns_answer` is green on the dev host.
4 changes: 2 additions & 2 deletions issues/build/a-shards-boot-width-does-not-price-its-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ reference and multiplies every liveness ceiling by the result; every shard print
it (`host: fastest boot N ms against the reference 1320 ms — liveness ceilings
paid at Wx width`). The proposal was to spend the same factor on the *duration
profile*: divide each shard's measured prices by its width in
`src/durations.rs`'s merge, so `src/tiers.rs`'s ceiling compares like with like
`35383398^:src/durations.rs`'s merge, so `src/tiers.rs`'s ceiling compares like with like
across shards of different speed, with timer-anchored names exempt because a
fixed wait does not shrink on a fast host.

Expand Down Expand Up @@ -132,7 +132,7 @@ renormalize.
## What is still true and is not this

The two-*machine* gap — twelve hosted EPYC shards against one T14 lane,
1.35–1.37x apart on an idle host, recorded in `src/durations.rs`'s header with
1.35–1.37x apart on an idle host, recorded in `35383398^:src/durations.rs`'s header with
the committed profile's `shards=` column naming which partition took each
price — is untouched by any of the above: that measurement is a gap between
machines, not a within-lane shard factor. This file says only that the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ then reclaims the killed run's directory — the very images those QEMU
processes still have open — and unlinks it while the guest is still alive,
holding the disk invisibly until the guest itself exits.

This is not a regression: the retired `src/scratch.rs` design (kept a killed
This is not a regression: the retired `96c2f83d^:src/scratch.rs` design (kept a killed
run's directory for 24 hours) had the identical gap for a killed run's QEMU
children, so #529 (which replaced that design) found it and correctly did not
block on it. It is unfixed either way and worth its own entry.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ error: could not compile `std` (lib) due to 2 previous errors
thread 'main' panicked at src/toolchain.rs:1583:5:
```

Afterwards `rust/build/aarch64-apple-darwin/stage2/` held only `lib/`, and
Afterwards `rust/build/aarch64-apple-darwin/stage2/` held only a `lib` directory, and
`rustc -vV` in `userland/` answered "'rustc' is not installed for the custom
toolchain 'toyos'". The lock log shows a second process (pid 31197) holding
the same step just before, so the step had already been attempted once.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ opened: 2026-09-26
The owner's ruling of 2026-09-26 puts every `asm!`, `global_asm!`,
`naked_asm!`, naked function and `core::arch::*` intrinsic inside an
architecture's own module: `kernel/src/arch/<arch>/`, the bootloader's
`src/arch/`, and `toyos-abi`'s per-arch syscall entry. `src/sourcegate.rs`'s
`bootloader/src/arch/`, and `toyos-abi`'s per-arch syscall entry. `src/sourcegate.rs`'s
`ARCH_RULES` enforces it. The kernel and the loader now hold none outside
those; what is left is declared in that table as an exception, each row
pointing here:
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading