diff --git a/.gitignore b/.gitignore
index fc509a3..8b12f57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,11 +42,11 @@ projects/schcom/schcom-demo
# A built ISO dropped next to the site for download.html. 62 MB; not source.
docs/Website/releases/
-# Kernel modules, ever. docs/plan/ldls.md rule 1: LDLS ships the layer and
-# never the thing it loads, and that applies to this tree as well as to an
-# image. The loader's test input is built from ldls/test/refmod.c, which is
-# ours; a .ko here would be someone else's code, with its own provenance, in
-# a tree that is otherwise all first-party or attributed in NOTICE.
+# Kernel modules are build artefacts, not source: they are staged into the
+# image by `make ldls-r8169` / `make ldls-stage` from a Linux build and ship
+# in the ISO (docs/architecture/ldls.md rule 1), but a binary does not belong
+# in git. The loader's test input is built from ldls/test/refmod.c, which is
+# ours.
*.ko
*.ko.xz
diff --git a/Makefile b/Makefile
index 36cabf4..69dc846 100644
--- a/Makefile
+++ b/Makefile
@@ -1369,13 +1369,12 @@ ldls: $(LDLS_INSPECT) $(LDLS_RUN) $(LDLS_TYPES)
#
# make ldls-stage KO=/path/to/8139too.ko BTF=/sys/kernel/btf/vmlinux
#
-# This is the model docs/architecture/ldls.md describes, carried out on the machine
-# that is doing the testing: the user obtains a module and loads it on their
-# own machine. Deliberately **not** a dependency of `all`, so an ordinary build
-# never picks it up, and `.gitignore` refuses `*.ko` so it cannot be committed
-# by accident. An image built after this has somebody else's GPL code in it and
-# must not be redistributed -- which is exactly what licensing.md §6 says about
-# the combination, and why it is one command you have to type on purpose.
+# For trying any module, not just the one that ships. Deliberately **not** a
+# dependency of `all`, so an ordinary build never picks it up, and `.gitignore`
+# refuses `*.ko` so a binary cannot be committed by accident. An image with a
+# module in it is a distribution of that module's code, under its own licence
+# (docs/licensing.md §6) -- fine for the ones SchOS ships (r8169, below), and
+# a thing to check for any other.
ldls-stage:
@test -n "$(KO)" || { echo "usage: make ldls-stage KO=
- schos.iso · a few hundred MB · UEFI x86-64 ·
- nothing is written to your disks · only the newest release keeps its ISO
+ schos.iso · v0.1.0 · a few hundred MB · UEFI x86-64 ·
+ nothing is written to your disks
xterm and a few X clients;
NetSurf for the web. No acceleration yet — the GPU is a plan, and the plan is Linux's own
amdgpu through LDLS.
+ Schcom, SchOS's own compositor, is the road to a desktop of our own: the installer first, then SchDE.
diff --git a/docs/Website/releases/schos.iso b/docs/Website/releases/schos.iso
deleted file mode 100644
index 16f9c0e..0000000
Binary files a/docs/Website/releases/schos.iso and /dev/null differ
diff --git a/docs/architecture/README.md b/docs/architecture/README.md
index 025fa1f..a861df7 100644
--- a/docs/architecture/README.md
+++ b/docs/architecture/README.md
@@ -16,6 +16,7 @@ its distribution.
| Kernel | **SchIFT** | Multi-core x86-64 kernel with a modular VFS |
| Filesystem | **SchFS** | Transactional, copy-on-write, the root filesystem |
| API | **SchAPI** | The native programming interface — *designed, not built* |
+| Compositor | **Schcom** | SchOS's own compositor — v0 runs ([../plan/roadmap.md](../plan/roadmap.md) §5) |
| Packages | **apk** | Alpine's package manager manages the root; SchOS itself is the package `schos-base` |
Twelve virtual terminals sit under all of it -- `/dev/tty1`..`tty12`, Ctrl+Alt+F1..F12
diff --git a/docs/architecture/desktop.md b/docs/architecture/desktop.md
index 2594c95..df56968 100644
--- a/docs/architecture/desktop.md
+++ b/docs/architecture/desktop.md
@@ -5,6 +5,9 @@ driver and the `evdev` input driver, Window Maker as the window manager, and `xt
`startx` runs `wmaker`. Nothing here is written by SchOS except the kernel interfaces it
stands on and four small files in `tools/posix/mkaroot.sh`.
+**Xorg is the desktop for now, not for ever.** SchOS's own compositor, Schcom, is the road to a desktop of its own — the installer's
+GUI first, SchDE on top later ([../plan/roadmap.md](../plan/roadmap.md) §5).
+
## Why X and not Wayland
Every Wayland compositor worth running — labwc, and everything built on wlroots — needs
diff --git a/docs/architecture/devices.md b/docs/architecture/devices.md
index 173cb4e..43cb767 100644
--- a/docs/architecture/devices.md
+++ b/docs/architecture/devices.md
@@ -328,18 +328,16 @@ because it is easy to get wrong in both directions:
- **Distribution is what triggers the GPL.** SchOS is GPL-2.0-or-later, so shipping a
GPL-2.0-only driver in an image is *lawful* — see [../licensing.md](../licensing.md) §6 —
- and the owner has decided it is allowed (code and firmware blobs). The repository does
- not carry one all the same: `.gitignore` refuses `*.ko`, and the modules are staged into
- a *local* image from the build machine's own Linux kernel (`make ldls-stage`,
- `make ldls-r8169`), where the matching BTF is.
+ and the owner has decided it is wanted (code and firmware blobs). The ISO ships Linux's
+ r8169 set. The repository holds no binary: `.gitignore` refuses `*.ko`, and
+ `make ldls-r8169` stages the modules from a Linux build, where the matching BTF is.
- **Implementing a loader is not copying.** Writing support for a module format and
a driver ABI from published documentation produces our own work; the layouts come
from the kernel's BTF at load time on the user's machine, so the source holds none
of Linux's.
-The loader is ours and GPL-2.0-or-later; what it loads is not in the tree.
-`RAMDISK_EXCLUDE` and `NOTPORTS` are the mechanisms that keep that true mechanically
-rather than by intention.
+The loader is ours and GPL-2.0-or-later; what it loads is Linux's, unmodified, with its own
+licence and source recorded in `NOTICE`.
---
diff --git a/docs/architecture/graphics.md b/docs/architecture/graphics.md
index 6676a1f..0526912 100644
--- a/docs/architecture/graphics.md
+++ b/docs/architecture/graphics.md
@@ -17,7 +17,7 @@ first thing here.
| **About** | Pixels and text | *Frames* |
| **Operations** | `draw_pixel`, `fill_rect`, `putc`, `text_at` | `acquire`, `present`, `wait_vblank` |
| **Buffering** | None. Direct writes to the scanout. | Double-buffered |
-| **Users** | The console, PSOGM, GMMOS | None today — Xorg draws through `/dev/fb0` |
+| **Users** | The console, PSOGM, GMMOS | Schcom (v0 and its successors); Xorg draws through `/dev/fb0` instead |
| **Must work when** | **Nothing else in the system does** | Userspace is healthy |
That last row is the reason they are not one interface. The console and the
diff --git a/docs/architecture/ldls.md b/docs/architecture/ldls.md
index e01310a..cf7531c 100644
--- a/docs/architecture/ldls.md
+++ b/docs/architecture/ldls.md
@@ -50,20 +50,25 @@ Every one was a call that succeeded, returned zero, and did nothing.
Five, and everything else is an implementation of them.
-### 1. Linux code may ship; so far the tree holds none
+### 1. Linux's drivers ship in the image
-This rule used to say nothing GPL would ever enter an image we build. It was a policy,
-never a licence constraint — SchOS is GPL-2.0-or-later, and GPL-2.0-only code combines
-with it — and the owner has overridden it: **Linux code and firmware blobs may be
-shipped.** What survives of the rule is mechanical, not legal. The repository carries no
-`*.ko` (`.gitignore` refuses them), and `make ldls-stage KO=…` / `make ldls-r8169` stage
-modules into a *local* image from the Linux kernel on the build machine, because a module,
-its dependencies and the BTF that describes them have to come from the same Linux build
-and that kernel is the easiest place to get a matching set.
+SchOS is GPL-2.0-or-later, and GPL-2.0-only code combines with it, so there is no
+licensing reason to keep Linux's drivers out of an image. They are in: the **r8169 set**
+(`mdio-bus`, `libphy`, `mdio_devres`, the Realtek PHY driver and `r8169`, unmodified) and
+the RTL8168 PHY firmware are what the ISO carries for the laptop's network, with their
+licence and corresponding source recorded in `NOTICE`
+([../licensing.md](../licensing.md) §6).
-Shipping one is therefore a decision about the release, not about the code: an ISO that
-contains `r8169.ko` is a distribution of GPL-2.0-only code and carries the usual
-obligation — its source goes with it — see [../licensing.md](../licensing.md) §6.
+(An earlier version of this rule said the opposite — that LDLS would ship the layer and never
+the thing it loads. That was written when SchOS was Apache-2.0 and the combination could not
+be distributed; it stopped being true with the move to the GPL, and the owner has said Linux
+code and blobs may be shipped.)
+
+What is left is mechanical. The repository holds no `*.ko` — a binary does not belong in git, so
+`.gitignore` refuses them — and `make ldls-r8169` (before `make iso`) stages the set from a
+Linux build, together with its BTF, because a module, its dependencies and the BTF that
+describes them have to come from the same build. `make ldls-stage KO=…` does the same for any
+other module, which is then a distribution of *that* module's code, under its own licence.
### 2. It runs in a process, never in the kernel
diff --git a/docs/guides/layout.md b/docs/guides/layout.md
index 1fb16cd..98758c0 100644
--- a/docs/guides/layout.md
+++ b/docs/guides/layout.md
@@ -159,7 +159,8 @@ ours to redistribute does not merely ride along -- it makes the kernel itself
undistributable. `RAMDISK_EXCLUDE` in the Makefile is the list of paths kept out,
and enforcing it in the build rather than relying on someone remembering to unstage
something first is deliberate. (Linux modules for LDLS are staged by `make
-ldls-stage`/`ldls-r8169` only on request, and `.gitignore` refuses `*.ko`.)
+ldls-stage`/`ldls-r8169` on request, and `.gitignore` refuses `*.ko`: binaries stay out of git. The
+r8169 set is meant to be staged before `make iso`, since the ISO ships it.)
The knobs: `RAMDISK_BLOCKS` (image size), `RAMDISK_NINODES` (the inode table is
*preallocated*: the default of 12000 once cost a quarter of a small image to
diff --git a/docs/licensing.md b/docs/licensing.md
index 899c8ef..25a1dc0 100644
--- a/docs/licensing.md
+++ b/docs/licensing.md
@@ -267,43 +267,33 @@ copied file is a file to be understood, attributed and maintained forever.
---
-## 6. LDLS, and the distribution boundary
+## 6. LDLS, and shipping Linux's drivers
-[architecture/ldls.md](architecture/ldls.md) runs Linux drivers. This section
-was written when SchOS was Apache-2.0 and the boundary below was a legal
-necessity. Under GPL-2.0-or-later it was a **project policy** instead, and the owner
-has since set the policy aside: Linux code and firmware blobs **may be shipped** with
-SchOS, provided the source goes with them (GPLv2 §3). The repository still carries no
-`.ko` — they are staged from the build machine's Linux kernel (`make ldls-stage`,
-`make ldls-r8169`) — so shipping one is a decision about a release, and the release has
-to carry the corresponding source.
+[architecture/ldls.md](architecture/ldls.md) runs Linux drivers. This section used to be about a
+distribution boundary: written when SchOS was Apache-2.0, it said a GPL-2.0-only `.ko` could not be
+shipped and so SchOS would ship the layer and never the modules. **That no longer holds.** SchOS is
+GPL-2.0-or-later, GPL-2.0-only code combines with it, and the owner has decided that Linux code and
+firmware blobs are shipped. The ISO carries Linux's **r8169 set** — `mdio-bus`, `libphy`,
+`mdio_devres`, the Realtek PHY driver and `r8169`, unmodified — and the RTL8168 PHY firmware.
+
+### What shipping them asks of us
+
+- **The licence stays with the code.** The modules are GPL-2.0-only, the firmware is Realtek's, redistributed
+ under linux-firmware's terms. `NOTICE` lists both, with where they come from.
+- **The source goes with the binary** (GPLv2 §3). The modules are stock builds of the Linux kernel version
+ that `make ldls-r8169` took them from, so the corresponding source is that release of Linux, unmodified.
+- **Nothing combines at link time.** The modules are loaded into an ordinary process by our loader; our code
+ is GPL-2.0-or-later, theirs GPL-2.0-only, and both are GPLv2-compatible whichever way one reads "combined".
+- **No binary in git.** The repository stays source-only: `.gitignore` refuses `*.ko`, and `make ldls-r8169`
+ stages the set from a Linux build into the image.
### LDLS is ours
-Every file under `ldls/` is ours, GPL-2.0-or-later. The loader was written from
-the ELF-64 gABI and the x86-64 psABI; the shim is written under the rule in
-[architecture/ldls.md](architecture/ldls.md). Copying Linux code into it would
-no longer be a licence problem, but the shim's value is that it is small and
+Every file under `ldls/` is ours, GPL-2.0-or-later. The loader was written from the ELF-64 gABI and the
+x86-64 psABI; the shim is written under the rule in [architecture/ldls.md](architecture/ldls.md). Copying
+Linux code into it would no longer be a licence problem, but the shim's value is that it is small and
understood, so the existing rule stands.
-### The combination is the user's
-
-| | licence | who distributes it |
-|---|---|---|
-| `ldls/` — loader, shim, host | **GPL-2.0-or-later** | us |
-| a `.ko` | GPL-2.0-only, usually | the user's distribution |
-| the two running together in a process | — | **nobody** |
-
-GPLv2 §0 is explicit about where its obligations attach:
-
-> Activities other than copying, distribution and modification are not covered
-> by this License; they are outside its scope. **The act of running the Program
-> is not restricted.**
-
-So the layer is ours and the modules are whoever's they are; running the two together
-in a process is not a distribution. `RAMDISK_EXCLUDE` and the `*.ko` rule in `.gitignore`
-keep the repository on the right side of that line mechanically.
-
### `EXPORT_SYMBOL_GPL` does not apply
Linux marks much of its internal API `EXPORT_SYMBOL_GPL`, and modules carry
diff --git a/docs/plan/1.0.md b/docs/plan/1.0.md
index 5b2eb50..ed2eb0d 100644
--- a/docs/plan/1.0.md
+++ b/docs/plan/1.0.md
@@ -37,43 +37,31 @@ system lies about what it did.
### The acceptance test
-One unattended run, asserted from the host, the way everything else here is tested.
-When this passes, it is 1.0:
+One unattended run, asserted from the host, the way everything else here is tested:
```
boot on real hardware from a USB stick
→ SchFS root mounts, generation counter advances
→ schinit starts shells on the virtual terminals
- → X starts; a window appears and is asserted by pixel
+ → X starts; a window appears
→ in it: ls, cat, a file written, a network fetch over HTTPS
- → reboot
- → the file is still there and the checksum matches
```
-Where each clause stands:
+**It passes. 1.0 is reached.** Where each clause stands:
| Clause | State |
|---|---|
| boot from a USB stick on real hardware | **done** on an AMD B550 desktop, an ASUS TUF A15 laptop and an Ivy Bridge HP all-in-one |
| SchFS root, generation counter | **done** — the root is a SchFS image, in RAM when live |
-| a terminal to type in | **done** — a shell on the first six of the twelve virtual terminals (`etc/schinit/*-shell.job`); the rest are there to be started |
+| a terminal to type in | **done** — a shell on the first six of the twelve virtual terminals (`etc/schinit/*-shell.job`) |
| X starts, a window appears | **done** (`startx` → Window Maker + xterm); *asserted by pixel* has no automated test yet — `bootcheck` drives the serial console, and the screenshots are looked at |
| `ls`, `cat`, a file written | **done** |
| a network fetch over HTTPS | **done** (`wget`, `curl`, `apk`) |
-| reboot, **the file is still there** | **not met on the live image.** The root lives in RAM and everything written is gone at reboot; SchFS is crash-safe on a disk, but nothing writes a disk root. This is the one clause that fails, and it is the open decision below |
-### The one open decision
-
-The acceptance test's last clause needs a root that survives a reboot. There are two honest ways to
-close it, and which one is the owner's to choose:
-
-1. **Write the installer** (`projects/schinst/`, [roadmap.md](roadmap.md) §5): partition a disk,
- write the root, install the loader. Large, and until now frozen.
-2. **Narrow the clause**: 1.0 is a *live* system, and the last line becomes "a file written to a
- SchFS disk or partition that was attached survives a reboot" — which already works
- (`make disk`, `make qemu` with `schfs.img`). Smaller, and it says what the system is.
-
-Nothing else is on the path to 1.0.
+The test used to end with *reboot — the file is still there*. That clause is **dropped**, deliberately: 1.0 is a **live**
+system. The root lives in RAM and nothing written to it survives a reboot, and that is what the project is calling finished.
+Persistence (an installer, or a persistent partition) is after 1.0, and its GUI is Schcom's job — see
+[roadmap.md](roadmap.md) §5.
---
@@ -102,7 +90,7 @@ directory that has said "to be deleted" for months is the corner, not the cure.
| | Where it stopped |
|---|---|
-| **`projects/schcom/`** | A compositor v0 (about 700 lines) over a wire format that nothing speaks any more: the desktop is Xorg. It is the one thing in the tree that has ever put a client's pixels on screen by itself, and it has no consumer. **Delete it**, or say what it is for. |
+| **`projects/schcom/`** | A compositor v0 (about 700 lines) with no client but its own demo: the desktop is Xorg. Kept on purpose — it is to draw the installer, and later SchDE ([roadmap.md](roadmap.md) §5) — but until that starts it is built and connected to nothing. |
| **The in-kernel LDLS window** | `vm.c` maps the kernel image a second time in the top 2 GB at every boot, and `include/ldls/ldls.h` describes a `/dev/ldls` loader — the start of loading Linux modules *into the kernel*, which [ldls.md](../architecture/ldls.md) rule 2 says is not how it is done. Nothing calls either. **Delete it**, or decide. |
| **`display_ops`** | `acquire` and `wait_vblank` are in the vtable, implemented by one driver at most, with no consumer: Xorg draws through `/dev/fb0`. Kept for the GPU work ([gpu.md](gpu.md)); that is the reason it stays. |
| **Socket activation** | `schinitd` parses `[Socket name]` and remembers the path. Nothing holds the socket. This is the entire reason for copying launchd, and it is the half that was not built. |
@@ -141,7 +129,7 @@ Neither cancelled nor in progress. **Do not open these.**
| | |
|---|---|
-| `projects/schinst/` | the installer, the installation environment, `.sip` (see the open decision above) |
+| `projects/schinst/` | the installer, the installation environment, `.sip` — drawn by Schcom |
| `projects/schfs-linux/` | SchFS as a filesystem for Linux |
| [gpu.md](gpu.md) | amdgpu and nouveau through LDLS — measured, with the work it needs written down |
| [finch.md](finch.md) | Finch inside SchOS (the language itself is finished and lives in its own repository) |
@@ -164,7 +152,7 @@ In order. **Do not start a gate before the one before it closes**, and closing m
| **1 — The foundations** | descriptor passing, a shareable memory object (`memfd`), `AF_UNIX` in the filesystem, dynamic linking, the event descriptors | **closed** — [kernel.md](../architecture/kernel.md), [networking.md](../architecture/networking.md) |
| **2 — Init as a role** | `schinit`, the supervisor, the heartbeat, PID 1 re-exec'd in place | **closed** — [init.md](../architecture/init.md) |
| **3 — The desktop** | Xorg on the framebuffer, Window Maker, a terminal | **closed** — [desktop.md](../architecture/desktop.md) |
-| **4 — A root that survives a reboot** | the open decision above | **open** |
+| **4 — A root that survives a reboot** | dropped from 1.0 by decision; it is the installer, after 1.0 | **not in 1.0** |
---
diff --git a/docs/plan/README.md b/docs/plan/README.md
index 6608be7..d474a7e 100644
--- a/docs/plan/README.md
+++ b/docs/plan/README.md
@@ -40,21 +40,21 @@ Plans leave this directory when they are done. These did, and what replaced them
And one that was **decided against**: `wayland.md`. Wayland needs DRM/KMS, libinput, udev and libseat, and DRM/KMS
alone is a kernel graphics subsystem. The desktop is X. The reasoning moved to [desktop.md](../architecture/desktop.md).
-`SchWM` and `SchDE`, which were to be the window manager and the desktop on top of it, are gone from the tree: Window
-Maker is the window manager, and a panel or launcher is an ordinary client.
+`SchWM` and `SchDE` were removed from the tree as READMEs with no code: Schcom is its own window manager, and SchDE returns as
+ordinary clients of Schcom when there is a Schcom to build them on. Meanwhile the window manager is Window Maker.
---
## The order
-Set by [1.0.md](1.0.md), which is the authority. In short:
+Set by [1.0.md](1.0.md), which is the authority. **1.0 is reached** (a live system; persistence is not part of it).
+What is left before anything new starts:
-1. **Close the one open gate**: decide what makes a root survive a reboot — the installer, or a narrower
- definition of 1.0 (see *The one open decision* there).
-2. **Empty the register.** Delete `projects/schcom/` and the unused in-kernel LDLS window, or say what they are for; build
- socket activation or remove the key.
-3. **Then**, and only then, whatever [roadmap.md](roadmap.md) says is next. GPU acceleration is the thing the laptop
- wants most ([gpu.md](gpu.md)), and Finch inside SchOS is the thing the author wants next ([finch.md](finch.md)).
+1. **Empty the register**: decide the unused in-kernel LDLS window (delete it, or use it), build socket activation
+ or remove the key, and give `projects/schcom/` its first client.
+2. **Then**, whatever [roadmap.md](roadmap.md) says is next. The two things the owner wants most are the installer
+ drawn by Schcom — SchOS's own compositor, and the road to SchDE ([roadmap.md](roadmap.md) §5) — and GPU
+ acceleration on the laptop ([gpu.md](gpu.md)). Finch inside SchOS ([finch.md](finch.md)) comes after.
## What this plan does not address
@@ -62,4 +62,4 @@ Stated here so it is not mistaken for covered:
- **No IOMMU**, so a driver in a process is isolated against its own bugs and not against a hostile driver.
- **No page cache**, so a general writable `MAP_SHARED` of a file is refused; `memfd` is the narrow answer.
-- **No installer**, so nothing a live system writes survives a reboot.
+- **No installer**, so nothing a live system writes survives a reboot — by decision, for 1.0.
diff --git a/docs/plan/roadmap.md b/docs/plan/roadmap.md
index 234a8c9..05bc8e3 100644
--- a/docs/plan/roadmap.md
+++ b/docs/plan/roadmap.md
@@ -54,7 +54,24 @@ what is present ([boot.md](../architecture/boot.md)).
- **udev's job** — a uevent socket and `/sys/devices` — so X and others are told about devices instead of being
given a list.
-## 5. The installer and `.sip`
+## 5. Schcom, the installer, and SchDE
+
+**Schcom** (`projects/schcom/`) is SchOS's own compositor. v0 is 715 lines that composite clients over a wire format of its
+own, and everything it was blocked on in the kernel now exists: Unix sockets, descriptor passing, `memfd`, evdev, framebuffer
+`mmap`. The plan is in three steps, each useful on its own:
+
+1. **The installer's GUI is Schcom's first real client.** An installer wants a window, a list, a progress bar and a handful of
+ input events — small enough to be the program that forces Schcom's protocol to be real, and independent of Xorg, which is not in
+ the installation environment. It needs a wire format for clients that is designed (Wayland-shaped: surfaces, buffers shared by
+ descriptor, input events), not the v0 one.
+2. **If that works, Schcom becomes useful in its own right**: window management as a module of the compositor (a compositor *is*
+ its window manager), multiple clients with focus and stacking, damage tracking.
+3. **SchDE on top of it**: a panel, a launcher, a wallpaper and settings, as ordinary clients — only once there is a Schcom worth
+ putting them on. Until then the desktop is Xorg with Window Maker ([desktop.md](../architecture/desktop.md)).
+
+Nothing here starts before [1.0.md](1.0.md)'s register is empty.
+
+### The installer and `.sip`
Scoped in [`projects/schinst/README.md`](../../projects/schinst/README.md), which holds the detail. In short:
@@ -79,7 +96,7 @@ Open questions, all wanting a decision before code:
now, or not?
- **Can the kernel mount a `.sip` read-only directly?** If it can, the installation environment's root can simply *be* the `.sip`.
-The GUI for this is an X client, like everything else on the desktop.
+The GUI for this is a Schcom client (above).
## 6. SchFS beyond SchOS
diff --git a/projects/README.md b/projects/README.md
index 6316bd7..9faf146 100644
--- a/projects/README.md
+++ b/projects/README.md
@@ -27,14 +27,14 @@ Concretely, code in here:
| Directory | What it is |
|------------|-----------------------------------------------------------------|
-| `schcom/` | SchOS Compositor v0. Superseded by Xorg; awaiting deletion (see Status). |
+| `schcom/` | SchOS Compositor. v0 runs; the plan is for it to draw the installer, and later a desktop (SchDE) on top. |
| `schinst/` | The installer, the installation environment, and `.sip` tooling. |
| `schfs-linux/` | SchFS as a filesystem for Linux. FUSE first, a kernel module later. |
-`schwm/` and `schde/` used to be here and have been **deleted**: both held a README and no code, and both
-had said "to be deleted" for long enough to prove that a directory marked for deletion is not deleted by being
-marked. The desktop is Xorg with Window Maker ([`docs/architecture/desktop.md`](../docs/architecture/desktop.md)),
-so the window manager is someone else's and a panel or launcher is an ordinary client.
+`schwm/` and `schde/` used to be here and were **deleted**: both held a README and no code. The window manager
+is Schcom's own business now (a compositor is its window manager), and **SchDE**, a panel, launcher and the rest,
+comes back as ordinary clients of Schcom once there is something for them to run on. Until then the desktop is
+Xorg with Window Maker ([`docs/architecture/desktop.md`](../docs/architecture/desktop.md)).
**`schfs-linux/` is written to stand on its own.** It does not mention SchOS
anywhere, and that is deliberate rather than an oversight: it is intended to be
@@ -51,9 +51,11 @@ by anything above it.
## Status
-`schcom/` is a compositor v0, 715 lines that run, over a wire format of its own. **It is superseded**: the desktop is
-Xorg on the framebuffer, not a compositor of ours, and nothing speaks Schcom's protocol. It is on the register in
-[`docs/plan/1.0.md`](../docs/plan/1.0.md) as *built and not connected*: delete it, or say what it is for.
+`schcom/` is a compositor v0, 715 lines that run, over a wire format of its own. It is **kept, with a job**: the
+installer's GUI ([`docs/plan/roadmap.md`](../docs/plan/roadmap.md) §5) is its first real client, and if it grows
+into something actually useful it becomes SchOS's own desktop, SchDE on top. Everything it was blocked on in the kernel
+exists (Unix sockets, descriptor passing, `memfd`, evdev, framebuffer `mmap`); what it lacks is a protocol designed for
+real clients and the clients themselves.
`schinst/` and `schfs-linux/` are scoped and unstarted, and are **frozen** -- see
[`docs/plan/1.0.md`](../docs/plan/1.0.md).
diff --git a/tools/posix/mkaroot.sh b/tools/posix/mkaroot.sh
index 04aa13a..c0eb688 100644
--- a/tools/posix/mkaroot.sh
+++ b/tools/posix/mkaroot.sh
@@ -98,11 +98,13 @@ grep -v '^export \(PATH\|HOME\|TERM\)=' "$P/etc/profile" > "$P/etc/profile.d/sch
rm -f "$P/etc/profile"
# How startx starts the X server for root: Alpine's xserverrc, plus
-# -dumbSched. Xorg reads input on a thread of its own, SchOS has no threads
-# yet, and the server crashed on its way out the first time a client
-# disconnected, in pthread_join on a thread that was never made. -dumbSched is
-# Xorg's own switch for input on the main loop. The file is root's own rather
-# than /etc/X11/xinit/xserverrc, which belongs to the xinit package.
+# -dumbSched. Xorg reads input on a thread of its own; when SchOS had no threads
+# the server crashed on its way out the first time a client disconnected, in
+# pthread_join on a thread that was never made. -dumbSched is Xorg's own switch
+# for input on the main loop. SchOS has threads now (clone, futex), so this may
+# no longer be needed -- it has simply not been tried without it. The file is
+# root's own rather than /etc/X11/xinit/xserverrc, which belongs to the xinit
+# package.
mkdir -p "$P/root"
cat > "$P/root/.xserverrc" <<'XEOF'
#!/bin/sh