SchOS/docs/Website/index.html
Nexoniarz 6490e5c759 site: rebuilt on Niveus, and the palette stops being a copy
Niveus is the interface language the project uses from here on -- this site
first, applications after it. Rebuilding the site on it is what proves the
system is one, rather than a folder of CSS with a README.

**`style.css` is gone.** 21 KB that transcribed include/theme.h by hand:
palette, type scale, shadows, spacing, every component. The intent was right --
"a site describing an operating system should look like the operating system"
-- and the mechanism was a copy, which means two files that have to be kept in
step by remembering to. What replaced it is `app.css`, which is layout and
nothing else, and one declaration in each page:

    :root { --nv-brand: #7C5CFF; }

That is SCH_ACCENT. Niveus derives the accent and its states, the link colour,
the focus ring, the tint in the greys and how far the status colours lean, for
light and dark both. One number to keep true instead of forty.

**The site is now adaptive.** Dark by default, because the OS is dark, with a
Light/Dark/Auto group in the bar that is real. The choice is kept in
localStorage and re-applied by an inline script before first paint, so the page
never renders in one appearance and corrects itself while you watch.

**PSOGM keeps its one purple, and now says so structurally.** #4B1D9A is
spelled the way Niveus spells a subtree with its own colour -- `data-nv-brand`
with its own `--nv-brand` on that section -- so every role inside re-derives
from it rather than being painted on. Still exactly one place, which is what
branding/README.md asks for.

Content is unchanged; what changed is what it is made of. Cards are `.nv-card`,
tags are `.nv-badge`, the support table is `.nv-table`, the crash section is a
`.nv-bed`, and the docs reader's two rails are `.nv-nav--vertical` with the
current document marked by `aria-current` rather than a class of our own.
`docs.js` emits `.nv-table` and `.nv-code`, so a change to the system reaches
the documentation too.

Three things were found by looking at it in a browser rather than by reading
it, and all three are the same mistake: **a `.nv-card` carries no padding of
its own -- its parts do.** The stat tiles, the "One ISO, one stick" band and
the card headers were all built from bare children, so numbers ran to the card
edge, the USB mark hung off it, and a title and its badge sat at opposite ends
of a row meant for a title and a trailing slot. Where the component had a right
way to say it, the markup now says it that way; where it did not -- a tile has
no parts -- `app.css` supplies the padding and says why.

Checked: every nv- class used across the three pages and docs.js exists in the
CSS, every token referenced by app.css is defined, and app.css contains no hex
value at all. Niveus's own tools/check.py passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 14:40:09 +02:00

648 lines
28 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SchOS — a 64-bit operating system written from scratch</title>
<meta name="description" content="SchOS is a from-scratch x86-64 operating system: the SchIFT kernel, the SchFS copy-on-write filesystem, a UEFI loader, and a userland that runs unmodified musl and toybox.">
<link rel="icon" href="Assets/shift.svg" type="image/svg+xml">
<!-- Niveus, and its optional continuity helpers. -->
<link rel="stylesheet" href="niveus/dist/niveus.css">
<script src="niveus/niveus/niveus.js" defer></script>
<!-- This site's own layout. No colours, no shadows, no type sizes. -->
<link rel="stylesheet" href="app.css">
<script>
/* Before first paint, so the page never renders in one appearance and then
corrects itself. Dark is the default because the OS is dark; the toggle
is real, and what it chooses is remembered. */
try {
var saved = localStorage.getItem("schos-theme");
if (saved === "system") document.documentElement.removeAttribute("data-theme");
else if (saved) document.documentElement.setAttribute("data-theme", saved);
} catch (e) { /* storage unavailable — keep the default */ }
</script>
<!-- The whole identity, and it is not a design decision: SCH_ACCENT, copied
from include/theme.h. A site describing an operating system should look
like the operating system. -->
<style>
:root { --nv-brand: #7C5CFF; }
</style>
</head>
<body>
<nav class="nv-nav" id="topnav" aria-label="Main" style="--nv-selection-name: nv-schos-nav">
<a class="nv-nav__brand" href="#top">
<img class="nv-nav__icon" src="Assets/shift.svg" alt="">
SchOS
</a>
<ul class="nv-nav__list">
<li><a class="nv-nav__item" href="#origin">Origin</a></li>
<li><a class="nv-nav__item" href="#stack">The stack</a></li>
<li><a class="nv-nav__item" href="#what">What it has</a></li>
<li><a class="nv-nav__item" href="#hybrid">Hybrid</a></li>
<li><a class="nv-nav__item" href="#numbers">Numbers</a></li>
</ul>
<span class="nv-nav__spacer"></span>
<a class="pride" href="#pride-note"
title="SchOS stands with the LGBTQIAP+ community — every month of the year">
<img src="Assets/pride.svg" alt="Progress Pride flag">
</a>
<div class="nv-button-group appearance" role="group" aria-label="Appearance">
<button class="nv-button nv-button--sm" data-nv-theme="light" aria-pressed="false">Light</button>
<button class="nv-button nv-button--sm" data-nv-theme="dark" aria-pressed="true">Dark</button>
<button class="nv-button nv-button--sm" data-nv-theme="system" aria-pressed="false">Auto</button>
</div>
<a class="nv-button nv-button--sm" href="docs.html">Docs</a>
<a class="nv-button nv-button--sm nv-button--primary" href="download.html">Download</a>
</nav>
<main id="top">
<!-- ====================================================================== -->
<header class="shell hero">
<div class="hero__copy">
<span class="nv-badge nv-badge--accent">
<span class="nv-badge__dot"></span>
SchIFT 0.1.0 · boots on real hardware
</span>
<h1 class="nv-display hero__title">
<img class="hero__mark" src="Assets/shift.svg" alt="">SchOS
</h1>
<p class="nv-prose">
A 64-bit operating system written from scratch — its own kernel, its own
filesystem, its own bootloader. It boots on UEFI, drives real hardware,
and runs unmodified <code class="nv-code">musl</code> and
<code class="nv-code">toybox</code> on top.
</p>
<div class="nv-cluster">
<a class="nv-button nv-button--primary nv-button--lg" href="download.html">Download it</a>
<a class="nv-button nv-button--lg" href="#what">What it has</a>
</div>
<p class="nv-caption">Apache-2.0 · runs from RAM · writes nothing to your disks</p>
</div>
<div class="nv-card nv-card--flush console" aria-label="Boot log">
<div class="console__bar">
<span class="nv-badge nv-badge--success"><span class="nv-badge__dot"></span>ttyS0</span>
<span class="nv-caption nv-text-tertiary">SchIFT</span>
</div>
<pre class="nv-code console__log" id="bootlog" aria-live="polite"></pre>
</div>
</header>
<!-- ====================================================================== -->
<section id="origin" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Origin</p>
<h2 class="nv-heading">It started as a teaching kernel and stopped being one</h2>
<p class="nv-prose nv-text-secondary">
SchOS began as <a href="https://github.com/mit-pdos/xv6-public">xv6</a>, MIT's
teaching operating system: 32-bit, single core, one filesystem, a few dozen
syscalls. Almost none of that survives. What follows is what replaced it.
</p>
</div>
<!-- A timeline, not a grid: these happened in this order, and the order is
the point. The rail is what carries that; the labels are its steps. -->
<ol class="timeline">
<li class="timeline__step">
<span class="nv-overline timeline__when">First</span>
<h3 class="nv-title">64-bit, and more than one core</h3>
<p class="nv-body nv-text-secondary">
Four-level paging, a real SMP bring-up, per-CPU state and a trap path
that survives both. This is the part that invalidates most of what a
32-bit uniprocessor kernel assumes.
</p>
</li>
<li class="timeline__step">
<span class="nv-overline timeline__when">Then</span>
<h3 class="nv-title">Its own filesystem</h3>
<p class="nv-body nv-text-secondary">
xv6's log-structured filesystem was replaced by <b>SchFS</b>: a
copy-on-write B-tree with an uberblock ring, extents and checksummed
metadata. A crash leaves either the old tree or the new one.
</p>
</li>
<li class="timeline__step">
<span class="nv-overline timeline__when">Then</span>
<h3 class="nv-title">A Linux-shaped ABI</h3>
<p class="nv-body nv-text-secondary">
The syscall table adopted Linux numbering, which is what makes an
unmodified musl and an unmodified toybox run. The table is one
<code class="nv-code">.inc</code> file, and it is the seam the whole
system is built around.
</p>
</li>
<li class="timeline__step">
<span class="nv-overline timeline__when">Then</span>
<h3 class="nv-title">Hardware, not emulation</h3>
<p class="nv-body nv-text-secondary">
A UEFI loader, xHCI and USB storage, an e1000 with a real TCP/IP stack,
virtio-gpu and VBE framebuffers, and a device model where a driver never
names its consumer.
</p>
</li>
<li class="timeline__step">
<span class="nv-overline timeline__when">Now</span>
<h3 class="nv-title">Drivers that are not in the kernel</h3>
<p class="nv-body nv-text-secondary">
A process can be handed a PCI device — its registers, its memory, its
interrupts — and drive it. The GPU driver already runs that way. Nobody
writes a driver for every device that exists; the answer is to stop
requiring that they live inside.
</p>
</li>
</ol>
</section>
<!-- ====================================================================== -->
<section id="stack" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Architecture</p>
<h2 class="nv-heading">Three seams hold the whole thing together</h2>
<p class="nv-prose nv-text-secondary">
Above the syscall table, software is ordinary and portable. Below the device
model, a driver never names its consumer and a consumer never names a driver.
And at <code class="nv-code">/dev/pci</code>, a driver stops needing to be in
the kernel at all. Everything else is arrangement.
</p>
</div>
<div class="nv-card nv-card--flush stack">
<div class="stack__layer">
<span class="nv-label stack__name">userland</span>
<span class="nv-body nv-text-secondary">toybox, mksh, zsh, musl, and the first-party programs in <code class="nv-code">cmd/</code></span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">userspace drivers</span>
<span class="nv-body nv-text-secondary"><code class="nv-code">vgpud</code> — a driver that is an ordinary process</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">schinit</span>
<span class="nv-body nv-text-secondary">PID 1 — job manifests, supervision, reincarnation</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">syscall table<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">Linux numbering, one <code class="nv-code">.inc</code> file — the ABI seam</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">kernel services</span>
<span class="nv-body nv-text-secondary">VFS, sockets and <code class="nv-code">SCM_RIGHTS</code>, signals, mmap, poll, procfs</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">subsystems</span>
<span class="nv-body nv-text-secondary">SchFS, lwIP, virtual terminals, graphics, the buffer cache</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">device model<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">class vtables and bus binding — the driver seam</span>
</div>
<div class="stack__layer stack__layer--seam">
<span class="nv-label stack__name">/dev/pci<span class="nv-badge nv-badge--accent nv-badge--square">seam</span></span>
<span class="nv-body nv-text-secondary">registers, DMA and interrupts to a process — the eviction seam</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">drivers</span>
<span class="nv-body nv-text-secondary">xHCI, e1000, virtio-gpu, VBE, IDE, PS/2</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">SchIFT core</span>
<span class="nv-body nv-text-secondary">scheduler, paging, traps, IRQ, SMP, DMA</span>
</div>
<div class="stack__layer">
<span class="nv-label stack__name">boot</span>
<span class="nv-body nv-text-secondary">the UEFI loader in <code class="nv-code">boot/uefi</code></span>
</div>
</div>
<p class="nv-body nv-text-tertiary section__note">
<code class="nv-code">uname -s</code> reports <b>SchIFT</b> — the kernel — the
way every Unix reports its kernel rather than its distribution.
</p>
</section>
<!-- ====================================================================== -->
<section id="what" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">What it has</p>
<h2 class="nv-heading">Built and running, and honest about the rest</h2>
<p class="nv-prose nv-text-secondary">
Every card marked <b>runs</b> is in the tree and works today. The tags are
not aspirational; the things that are not finished say so.
</p>
</div>
<div class="nv-card-grid">
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title"><img class="cardmark" src="Assets/uberblock.svg" alt="">SchFS</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Copy-on-write B-tree, a 128-slot uberblock ring, extents with refcounts
and reflink, CRC32c on metadata, and free space derived from the tree
rather than stored beside it — so there is no second structure to
disagree with the first. There is nothing to repair after a crash.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">SMP x86-64 kernel</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Four-level paging, multiple cores, preemptive scheduling, a calibrated
LAPIC timer, real signal delivery and job control. 207 syscalls on
Linux numbering.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">Networking</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
An e1000 driver under lwIP, with sockets for AF_INET, AF_UNIX and
AF_NETLINK. DHCP brings the interface up at boot;
<code class="nv-code">ping</code> reaches the outside world.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">UEFI boot</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
A PE/COFF loader built with clang and lld-link that sets up its own page
tables and hands the kernel a framebuffer. No BIOS path, no chainloading.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">USB</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
xHCI, hubs, HID and mass storage — a keyboard and a USB disk that the
kernel can mount, through the same device model as everything else.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">Virtual terminals</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
Six of them, each with its own cell grid, scrollback and foreground
job — switched with <code class="nv-code">AltGr+F1</code>…<code class="nv-code">F6</code>,
which is the one chord a Linux host does not take for itself. The console
draws to whichever framebuffer is present, from the kernel's first line.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">schinit</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
PID 1 does almost nothing: it forks a supervisor, spawns jobs on its
behalf, and reaps. The supervisor holds the manifests and the respawn
policy, and if it dies PID 1 replaces it and hands back the children it
was already watching. PID 1 can re-exec itself without dropping them.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">A real userland</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
musl and toybox, both unmodified, plus mksh as <code class="nv-code">/bin/sh</code>.
<b>fastfetch</b> builds from upstream source with an empty
<code class="nv-code">patches/</code> directory — when it could not detect
something, the answer was to give the kernel what it was looking for.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">Drivers outside the kernel</h3>
<span class="nv-badge nv-badge--success">runs</span>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">/dev/pci</code> hands a process a device: its
registers by <code class="nv-code">mmap</code>, physically contiguous
memory it can point the device at, and interrupts as something to
<code class="nv-code">read()</code>. The virtio-gpu driver already lives
out there.
</div>
<div class="nv-card__footer nv-card__footer--plain">
<a class="nv-button nv-button--ghost nv-button--sm" href="#hybrid">How that works →</a>
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">Schcom</h3>
<span class="nv-badge nv-badge--warning">in progress</span>
</div>
<div class="nv-card__body nv-text-secondary">
The compositor that will own the display. v0 runs, and descriptor
passing — the one thing a Wayland client cannot do without — now
exists. What a buffer still needs is a shareable memory object.
</div>
</article>
<article class="nv-card">
<div class="nv-card__header">
<h3 class="nv-card__title">SchAPI</h3>
<span class="nv-badge">designed</span>
</div>
<div class="nv-card__body nv-text-secondary">
The native programming interface — specified, not built, and deliberately
so. It should be designed <i>from</i> the compositor's experience rather
than before it.
</div>
</article>
</div>
</section>
<!-- ====================================================================== -->
<section id="hybrid" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Hybrid</p>
<h2 class="nv-heading">A driver can leave the kernel</h2>
<p class="nv-prose nv-text-secondary">
Nobody writes a driver for every device that exists — not a project this
size, and not any project. So the interesting question is not how to write
more of them, but what a driver actually needs from a kernel, and whether it
can have that from outside.
</p>
</div>
<div class="needs">
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">Its registers</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">mmap</code> on <code class="nv-code">/dev/pci</code>,
where the offset is the physical address of a BAR. The kernel refuses any
offset that is not inside a BAR of a device this process was given, which
is what stops it being <code class="nv-code">/dev/mem</code> with extra steps.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">Memory the device can reach</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
Physically contiguous, and the process is told the physical address —
which is the whole reason it cannot do this for itself. The arena is
reserved at boot, before the general allocator gets anything.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">To be told when to look</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
Interrupts arrive by <code class="nv-code">read()</code>, so they compose
with <code class="nv-code">poll</code>. The kernel masks the line and
leaves it masked until the driver writes back — because a PCI interrupt is
level-triggered, and nobody but the driver knows how to clear it at the device.
</div>
</article>
<article class="nv-card nv-card--inset">
<div class="nv-card__header">
<div class="nv-stack nv-stack--tight">
<p class="nv-overline nv-text-tertiary">It needs</p>
<h3 class="nv-card__title">A descriptor to arrive</h3>
</div>
</div>
<div class="nv-card__body nv-text-secondary">
<code class="nv-code">sendmsg</code> with <code class="nv-code">SCM_RIGHTS</code>.
Handing a process the device it is allowed to touch and handing a
compositor a buffer turned out to be the same act, which is why one
primitive answered both.
</div>
</article>
</div>
<div class="nv-card nv-card--flush console" aria-label="Evicting the GPU driver to userspace">
<div class="console__bar">
<span class="nv-badge nv-badge--success"><span class="nv-badge__dot"></span>tty1</span>
<span class="nv-caption nv-text-tertiary">vgpud</span>
</div>
<pre class="nv-code console__log"><span class="nv-text-tertiary">$ </span>vgpud
<span class="nv-text-accent">vgpud</span>: virtio-gpu at 00:03.0, currently held by virtio-gpu
<span class="nv-text-accent">virtio-gpu</span>: released to userspace; screen is the VBE framebuffer
<span class="nv-text-accent">vgpud</span>: claimed
<span class="nv-text-accent">vgpud</span>: display is 1280x800
<span class="nv-text-accent">vgpud</span>: scanout is ours, framebuffer at physical 0x3eceb000
<span class="nv-text-success">vgpud</span>: <span class="nv-text-success">mirroring the console</span>
</pre>
</div>
<p class="nv-body nv-text-tertiary section__note">
<b>No syscall in that transcript knows it is talking about a GPU.</b> The
kernel handed over a PCI device; the process decided what it was. That is
the property that makes the interface general — and the reason SchOS's own
drivers are being moved out through it first, rather than shaping it around
something foreign and hoping it fits.
</p>
</section>
<!-- ====================================================================== -->
<section id="numbers" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Numbers</p>
<h2 class="nv-heading">The size of it</h2>
</div>
<div class="figures">
<div class="nv-card figure">
<b class="nv-display figure__value">46,961</b>
<span class="nv-label nv-text-secondary">lines in <code class="nv-code">kernel/</code> and <code class="nv-code">include/</code></span>
</div>
<div class="nv-card figure">
<b class="nv-display figure__value">207</b>
<span class="nv-label nv-text-secondary">syscalls, Linux numbering</span>
</div>
<div class="nv-card figure">
<b class="nv-display figure__value">0</b>
<span class="nv-label nv-text-secondary">patches carried against fastfetch</span>
</div>
</div>
</section>
<!-- ======================================================================
PSOGM. The one place this purple is allowed, so it is spelled the one
way the system allows a subtree to carry its own colour: re-derive the
whole set from it, and let every role follow. -->
<section class="shell section" data-reveal>
<div class="nv-bed nv-bed--single crash" data-nv-brand style="--nv-brand: #4B1D9A">
<span class="nv-bed__label">When it stops</span>
<img class="crash__mark" src="Assets/shift.svg"
alt="Shift, the SchOS mark, as the crash screen draws it">
<div class="crash__copy">
<h2 class="nv-heading">PSOGM</h2>
<p class="nv-prose">
When the kernel panics it does not scroll a stack trace past you. It draws
a full-screen report — what failed, where, and the state that mattered —
and encodes the whole thing as a QR code so it can leave the machine
without being retyped. It reaches every display the machine has, including
the ones the kernel has handed to a userspace driver.
</p>
<p class="nv-prose nv-text-secondary">
This purple is <code class="nv-code">#4B1D9A</code>, and the theme reserves
it for exactly this. Normal states are calm and dark; only failure is loud.
It is the one colour in the system that means something, which is why it
appears once on this page and nowhere else.
</p>
</div>
</div>
</section>
<!-- ====================================================================== -->
<section id="docs" class="shell section" data-reveal>
<div class="section__head">
<p class="nv-overline nv-text-accent">Reading</p>
<h2 class="nv-heading">Where to look</h2>
<p class="nv-prose nv-text-secondary">
The documentation is written to outlive the work. Anything finished is
described in <code class="nv-code">architecture/</code>; anything intended
lives in <code class="nv-code">plan/</code>; and the bugs worth remembering
are kept in <code class="nv-code">history/</code>, in full, including the
wrong turns.
</p>
<p><a class="nv-button nv-button--primary" href="docs.html">Open the docs reader</a></p>
</div>
<div class="nv-card-grid">
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=architecture/README.md">Architecture</a>
</h3>
<p class="nv-card__subtitle">What the system is, layer by layer</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=plan/1.0.md">The 1.0 definition</a>
</h3>
<p class="nv-card__subtitle">What is in, what is out, and why</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=history/kernel.md">Kernel history</a>
</h3>
<p class="nv-card__subtitle">The bugs, and what each one taught</p>
</div>
</div>
</article>
<article class="nv-card nv-card--interactive">
<div class="nv-card__header">
<div>
<h3 class="nv-card__title">
<a class="nv-card__link" href="docs.html?doc=guides/building.md">Building it</a>
</h3>
<p class="nv-card__subtitle">Toolchain, ports, and running under QEMU</p>
</div>
</div>
</article>
</div>
</section>
<!-- ====================================================================== -->
<section class="shell section" data-reveal>
<div class="nv-card nv-card--elevated getband">
<img class="getband__mark" src="Assets/usb.svg" alt="">
<div class="getband__copy">
<p class="nv-overline nv-text-accent">Try it</p>
<h2 class="nv-heading">One ISO, one stick, nothing written to your disks</h2>
<p class="nv-prose nv-text-secondary">
It runs from RAM and leaves the machine as it found it. Or skip the
stick entirely — <code class="nv-code">make qemu</code> is the same
system in a window.
</p>
<div class="nv-cluster">
<a class="nv-button nv-button--primary" href="download.html">Download SchOS</a>
<a class="nv-button" href="docs.html?doc=guides/building.md">Build it instead</a>
</div>
</div>
</div>
</section>
</main>
<footer class="shell site-footer">
<div class="nv-divider"></div>
<div class="site-footer__row">
<span class="nv-body">SchOS — kernel <b>SchIFT</b>, filesystem <b>SchFS</b>.</span>
<span class="nv-code nv-text-tertiary">Apache-2.0, with the xv6-derived core under MIT.</span>
</div>
<p class="nv-body nv-text-secondary pride-note" id="pride-note">
<img src="Assets/pride.svg" alt="">
Built by, and for, people of every orientation and gender identity.
The flag stays up all year.
</p>
<p class="nv-body nv-text-secondary nv-prose" id="ai-note">
<b class="nv-text-primary">On AI.</b>
Parts of SchOS were written with AI assistance, and that is not the measure
of anything. A project is good when the people building it understand what
was built, and bad when nobody does — whoever, or whatever, typed it. Vibe
your way through and you get something no one can fix. Stay in the loop and
you get a system you can explain line by line. The bug writeups in
<a href="docs.html?doc=history/kernel.md">history/</a> are where that gets
checked, including the wrong turns.
</p>
</footer>
<script src="app.js"></script>
</body>
</html>