P8X Resident Window Manager — design¶
Status: the ladder is complete (2026-09-04). The resident kernel
draws windows (chrome, titles, card-list content) that outlive the app,
its event loop takes keyboard + grab-relative mouse-drag input, it
LAUNCHES an app and RESUMES with every window intact
(wm_launch_test), and each window keeps a resident STATE blob so apps
remember their place across launches (wm_switch_test). Chrome polish
(multi-window focus/close/menu) and the deluxe full-suspend switcher
are optional follow-ons; the core resident-WM goal is met.
Why resident, and why assembler¶
The C window system (rungs 1–4, desk + lib_wm + lib_ptr) proved the
mechanism — per-window hardware clipping, painter's repaint, menus, a file
browser, a picture viewer, and launching programs the System-1 way
(SYS_EXEC). But that desk is a 36 KB TPA program: launching an app
means replacing desk in memory and chaining back on exit. There is no
"switch between running windows" because there is only one program at a time
and desk is not one of them while an app runs.
The key idea: make desk resident (like the shell), so launching a program into the TPA does not destroy it. Then a saved-context scheme can switch focus between windows.
The obstacle is memory. The WM core alone (lib_wm + lib_ptr + the C
runtime, no browser/viewer/terminal) compiles to 17.6 KB — too big to sit
resident alongside a TPA large enough for real apps in 56 KB of RAM. So the
resident kernel must be hand assembler, like the OS: the project's own
C-vs-asm ratio (2.3–5.8×) puts it at ~4–6 KB.
Memory layout¶
Boot is unchanged: monitor → B → shell. The GUI is opt-in — but the
kernel needs no loading at all: it is part of the OS image, resident from
boot, reached through the OS syscall table.
$1800..$1FFF RAM island (freed by the 6K ROM 2026-09-14): IBUF, PATHBUF,
APBUF, SBUF $1D00, BIOS/FS scratch $1F00 — see gen_memmap.py
$2000 OS (resident) — INCLUDING the WM kernel (syscalls $2027-$204B)
~$5586 end of the OS+kernel image
$5700..$58FF OS scratch (LINEBUF, CWDPATH, FS/shell/make vars)
$5900 TPABASE ── full TPA for apps ($5900..CSTACKTOP, ~39.8 KB) ──
$F800 CSTACKTOP apps' C stack top
$F800..$F9FF shell command-history ring (8 × 64 B)
$FA00..$FBFF FSDIRBUF: the C commands' dir/glob sector page (dir, cat, glob_expand)
$FC00..$FDFF RDBUF: the C commands' shared file-read buffer
$FE00..$FEFF hardware (P3) stack, grows down from STKTOP
The kernel body (os/wmkernel_body.asm) is .included at the end of
p8xos.asm and exposed as six syscalls right after SYS_EXEC: $2027
SYS_WKINIT, $202A SYS_WKOPEN, $202D SYS_WKREPAINT, $2030 SYS_WKRUN,
$2033 SYS_WKSAVE, $2036 SYS_WKLOAD. Apps load into the full TPA with
the normal C stack — nothing is compiled with a special --cstacktop, no TPA
is surrendered. The OS image grew from 12.4 KB to 15.2 KB.
Why the history ring moved. The old map called $51C5..$6000 the "OS
growth reserve", but it was never free: the shell's 2 KB command-history ring
sat at $5800..$5FFF and its tab-complete scratch at $5700. Folding the
kernel in grew the image to $5B4C — straight into the ring — and every typed
command line overwrote live kernel code with ASCII (the crash trace showed
wk_draw executing the bytes of "un /bin/d"). OS + kernel + a 32-line
history cannot fit in 16 KB in any arrangement, so the ring shrank and moved
above CSTACKTOP — to $F800, and to 8 lines, because only $F800..$F9FF
(512 B) is free up there: $FA00 is the commands' FSDIRBUF dir/glob page and
$FC00 their RDBUF read buffer — fixed #defines in lib_*.c, invisible to a
memmap-anchor search, which is how a first 16-line attempt briefly overlapped
FSDIRBUF. The completion scratch moved to $5F00. All single-sourced in
gen_memmap.py; the ring code is fully symbolic (#HISTN-1 mask,
#>HISTRING), so no shell code changed.
The 36 KB C desk also runs in the full TPA; it is superseded by the resident
kernel, not broken by it. (History: the kernel was first a standalone blob at
$D800 above the TPA — a 28 KB app cap, and it collided with desk — then
briefly at $5600, which sat inside the history ring; both retired 2026-09-07.)
The card-resident-list lever¶
The enabling trick, already proven in rung 2: window content can live as a
card-resident command list (CLBEG/CLEND on the graphics card). The card
holds the picture, so the resident kernel redraws any window with CLRUN
(two wire bytes) — even after the program that drew it has left the TPA. A
window's content survives its author. This is what makes both later
task-switching options work, and it keeps the kernel's per-window cost tiny
(a rect, z-order, title, and a list id).
The exception is the terminal window: TEXT cannot be recorded into a
list (the documented limitation), so the kernel owns terminal content
directly — a small ring of text lines redrawn by resident code.
Kernel surface (syscalls, planned)¶
Appended to the OS syscall table after SYS_EXEC ($2024):
SYS_WMOPEN(rect, title, kind)→ window id. Register a window;kindselects content backing (card-list id, terminal, or app-drawn).SYS_WMCLOSE(id),SYS_WMRAISE(id),SYS_WMMOVE(id, x, y).SYS_WMLIST(id)→ the card-list id to record content into.SYS_WMRUN()→ hand control to the kernel event loop; returns when the user quits the GUI (or never, until then). Launches areSYS_EXECfrom inside the loop, and because the kernel is resident, the loop resumes when the launched app exits.SYS_WMEVENT()→ for apps that want to cooperate with the loop rather than own the screen: one pointer/key event, kernel-routed to the focused window.
desk becomes a ~1 KB launcher with no loading step at all: SYS_WKINIT,
SYS_WKOPEN its windows, then SYS_WKRUN. The kernel is already resident.
Build ladder¶
- Foundation — DONE 2026-09-04.
WMBASEreserved;p8cc --cstacktop;wm_reside_testproves the high region survives launches. - The kernel skeleton (asm) -- DONE 2026-09-04.
os/wmkernel.asm, assembled at WMBASE, loaded once by a stub via FRESOLVE+FFIND+FLOADAT. A bios()-callable jump table (WMBASE+0/3/6 = wk_init/wk_open/wk_repaint, +9 = 'WM' signature). Window records are copied RESIDENT (22 bytes each, up to 4); wk_repaint sets the text camera (RESETF, PROJCT 0 so z=0 TEXT is not near-clipped, MDIDEN, TSIZE), identity WINDOW/VWPORT, FLOODs the desktop, and draws each window's chrome + stroke-font title from the records.wm_kernel_testproves it: a stub opens two windows and EXITS, then a SEPARATE program calls wk_repaint and nothing else -- the two titled windows reappear, drawn wholly by the resident kernel from records the departed app left behind. ~1KB of the ~10KB budget. Traps:.org $WMBASEis required (pc starts at 0 even with --base); bios() needs a literal address (precompute WMBASE+3, not an expression); and -- the debugging saga of the rung -- a test thatexits to the monitor gets its frame BLANKED (the console reclaiming the screen at wake -- in that build, the boot splash), so GUI frame tests must dump at the shell, never the monitor. - Content lists -- DONE 2026-09-04; events next. wk_draw maps each
window's content rect (WINDOW/VWPORT, the lib_wm mapping) and replays
its card list with
CLRUN-- so window content lives on the card and redraws when the app is gone.wm_kernel_testnow proves it end to end: the stub records a red box into card list 40, opens SHAPES with that list, and EXITS; the redraw-only program's frame still shows the red content, drawn by the resident kernel from a list on the card. THE REAL BUG this rung surfaced: RESETF clears the card command lists (memset(cldef,...)), so a resident repaint must never RESETF -- it sets PROJCT 0 / MDIDEN / TSIZE directly instead. Events are next:lib_ptr-equivalent parsing in asm (or a small resident C helper the kernel calls), focus, drag, close, the menu. - Launch + resume — DONE 2026-09-07, as a real program.
wdeskis the thin launcher:SYS_WKINIT,SYS_WKOPENits windows (SHAPES with a card-list scene),SYS_WKPATH "/bin/paint.bin -w",SYS_WKRUN. Pressinglmakes the kernelSYS_EXECpaint OVER wdesk; paint, seeing-w, callsSYS_WKRUNon quit and the desktop returns with every window and its card-list content intact.c_wdesk_testproves it end to end. The newSYS_WKPATH($2039) makes the launch target the client's choice (the default/bin/wapp.binkeeps the WM tests' client). This is the payoff — the desktop survives launching an app — whichdesk(WM in the TPA) cannot do. - Focus + close boxes in the kernel — DONE 2026-09-07. Focus IS the top
record:
k_raisemoves a record to the top slot (TAB raises the bottom window; a mouse press hit-tests ALL windows top-down viak_hitand raises the hit one).wk_drawgives every window desk's chrome — a 14-row title bar, white when focused and grey otherwise, a 9×9 black close box atx+3..x+11, black title text atx+16; pressing the close box pops the (now top) record.wm_focus_testproves TAB, the bar colours and the close. Cost: +673 B — the OS image now ends$5E16, 234 B short of the completion scratch at$5F00. THE WALL. A menu bar with a press-slide-release pull-down is ~400 B of this asm and does not fit; FILES, TERM and VIEW (thousands of bytes) never will. The OS image is at the 16 KB cap, so the kernel must stay a SMALL resident core — windows, z-order, chrome, drag, launch-and-resume — and the rich UI belongs in the CLIENT, which has the 37 KB TPA. SYS_WKEVENT— the client-driven loop — DONE 2026-09-07.wk_run's internal loop is now a one-event step,wk_event(SYS_WKEVENT,$203C): it handles the events the kernel owns (TAB focus, arrows, mouse press/drag/ release → raise/drag/close) and returns to the client — carry set = quit, elseA = 0(kernel handled it) or the key byte the kernel does not own.SYS_WKRUNbecomes a thin loop over it, so every existing test still passes (behaviour unchanged) at +20 B.wm_event_testproves a client drives the loop: the kernel moved the window on an arrow and handed the client an unownedx. This is the split that lets the rich desktop live in the client:wdeskcan now draw its own menu bar and run FILES/TERM/VIEW, acting on the keys and (next) the menu-bar clicks the kernel returns, while the kernel keeps the windows alive across launches.- The client's menu bar — DONE 2026-09-07.
wdeskis now a realSYS_WKEVENT-driven client with its own menu bar (DESK L=PAINT C=CLOSE Q=QUIT, drawn in the top rows by the client, not the kernel). It drives the kernel one event at a time; the kernel handles window mechanics and returns the keys it does not own, and the bar acts on them: L launches paint over wdesk, C closes the top window (the one new kernel primitive,SYS_WKCLOSE$203F, +14 B), Q/^Dquits. The launch/resume now brings back the client: paint-wre-execswdesk -r(RESUME: windows are in the kernel, so it just redraws them and the bar) instead of the kernel's bareSYS_WKRUN.c_wdesk_testproves the bar is drawn, the launch runs paint, and the resume restores windows + content + bar. The rich UI is in the client (37 KB TPA); the OS grew only the 14-byte primitive. - A CLICKABLE menu bar — DONE 2026-09-07.
SYS_WKEVENTnow returns a third kind of event: a mouse press in the top rows (cell y ≤ 2, below no window) comes back asA = 2with the cursor column in a new one-byte accessorSYS_WKARG($2042). Keys likewise moved behindSYS_WKARG(eventA = 1, byte viaSYS_WKARG), so theSYS_WKEVENTreturn is now a clean event code (0 handled / 1 key / 2 bar-click / carry quit).wdeskdraws its words (DESK PAINT CLOSE QUIT) at known columns and maps a click's column to the same action as the L/C/Q keys.wm_barmenu_testclicks the CLOSE zone and the window closes. Gotcha fixed: an accessor that returns a value mustCLC—SYS_WKARGfirst returned a stray carry, whichbios()folded in as bit 256 (26 → 282), picking the wrong action nondeterministically. Kernel headroom is now ~143 B before$5F00— the core is nearly full, as intended. - FILES — a directory listing in a client-drawn window — DONE 2026-09-07
(read-only). The content model that FILES / TERM / VIEW all need: the
kernel exposes a window's rect (
SYS_WKGET$2045, index inA, record →P1) and the top index (SYS_WKTOP$2048).wdeskopens a FILES window, reads the CWD once (FOPENDIR/FNEXT, cached — not per repaint), and after each kernel repaint draws the entries as stroke text inside the window: it setsWINDOW/VWPORTto the body (desk'swm_vwinidiom,cw=w-2,ch=h-15) so the card clips the text to the window, then restores the identity camera for the menu bar. It draws the listing only when FILES is the top window (SYS_WKTOP), so client-drawn dynamic content composites correctly without a full kernel compositor.c_wfiles_testproves the listing text is in the window body while SHAPES' card-list content coexists. The kernel is now essentially full: ~94 B before$5F00. Further window accessors are cheap, but no more sizable kernel code fits — which is the point: FILES selection + open, TERM, and VIEW are all CLIENT work from here (in-window clicks/keys can ride the existingSYS_WKEVENTreturn; a content callback is the alternative if per-window compositing is needed). Next: FILES selection + open (click a row → launch a.BIN/ navigate a dir), then TERM, then the asm/bintwin. - FILES is now interactive — DONE 2026-09-07 — pure client, no kernel
change. With FILES focused,
n/pmove a highlighted selection (the selected row is drawn yellow, the rest cyan-for-dir / white-for-file) andENTERopens it: a directory re-reads the CWD intowdesk's cache and relists (../.go up), a.BINlaunches viaSYS_EXECwith-wso it resumes the desktop on quit, other files are skipped. Keys that FILES does not own still fall through to the menu-bar letters. This validated the rung-10 content model end to end — the kernel handed over only the window rect and the unowned keys; selection, the directory cache, navigation and launch are all in the ~37 KB TPA client. The p8cc unsigned-compare trap bit here: the "no action" sentinel was-1, but p8cc compares are UNSIGNED, soa = -1; a >= 0is true (-1==0xFFFF); non-menu keys fell intoact(-1)→ the defaultreturn 1→ quit. Fixed with a99sentinel and an explicita < 3test (in both the key branch and the bar-click branch, andact_atreturns99).c_wfiles_testnow also asserts the selection moves onnand thatENTERchanges the listing. - TERM — a command line in a client-drawn window — DONE 2026-09-07 — and
windows are now addressed by TITLE, not index. TERM is a scrollback
(5 lines) plus an input line, drawn by
wdeskin its window body exactly like FILES. While TERM is focused it owns the whole keyboard (sol/c/qtype, they do not fire the menu — the bar stays clickable);ENTERruns the typed line, resolved the way the shell resolves a bare command (absolute path as typed, else/bin/<name>,.binappended when missing) and launched with-w, so a WM-aware app resumes the desktop and a failed exec shows?EXEC. It is a launcher with history, like desk's TERM —SYS_EXECbecomes the program, so TERM does not capture a program's output (that is the per-window tty, a separate later rung). The rung forced a real fix:k_raisePHYSICALLY REORDERS the window records, so a fixed array index (files_win = 1) does not track a given window across any focus change — the rung-10/11 FILES code only worked because its test never changed focus first. wdesk now identifies the focused window by the FIRST LETTER of its title (S/T/F), which rides in the record and is stable across reorders:content_draw()reads the top window's record (SYS_WKGETofSYS_WKTOP) and dispatches ontitle[0], and the key router does the same. This both enables TERM and fixes the latent FILES-after-TAB bug. Three windows now (SHAPES/TERM/FILES) against the kernel'sMAXWIN4, no kernel change.c_wterm_testproves it by frame-hash differentials (focus, typing and submit each change the frame) plus a pixel check that the white scrollback GROWS when a command is submitted (SHAPES has no white and TERM is on top of its region, so that white is TERM's own). - VIEW — a picture window — DONE 2026-09-07 — and a small kernel primitive,
SYS_WKRAISE. Opening a.p8ifrom FILES opens a VIEW window sized to the image and streams the picture into its body, one cardBLITper row — desk'sdrawview, moved into a kernel window via the rung-10 content model (WINDOW/VWPORTto the body, re-read from disk each repaint, no framebuffer). VIEW is the on-demand 4th window (MAXWINis 4): the first.p8iopens it (added on top = focused); a later.p8ire-fronts the same window. That re-front is the one thing the client could not do — z-order is the kernel's, and onlySYS_WKEVENT's TAB raised anything — so this rung addsSYS_WKRAISE($204B):A= window index → raise it to top. It just exposes the existing internalk_raise, so it is ~7 bytes (OS ends$5EAA, 86 B before the$5F00ceiling). The client turns a title back into the index the syscall needs withwin_index()(scan the records for the title letter) — the exact inverse of title-dispatch. Adding a z-order primitive to the kernel is on-strategy (mechanism in the kernel, policy — which window — in the client), unlike the UI, which stays out.c_wview_testopens a 40×30 green.p8iand asserts ~1200 green pixels appear inside a VIEW window that was not there before. Note the cost model: with no framebuffer the image re-streams from disk on every repaint, so dragging VIEW is slow — a per-window content cache is a later refinement. - Saved per-window context (the switcher): each window keeps its app's state; focus-switch swaps the active TPA (state-only first, full-TPA-swap to disk as the deluxe variant — the two later options from the fork).
Per-window command output — the OUTCH→window sink (design, 2026-09-08)¶
The endgame: type dir (or cat, wc, any text command) in a window and see
its output in that window, with ZERO changes to the command. This is the
"real TERM" the launcher-TERM (rung 12) stands in for. It is a multi-rung OS
change; this section fixes the architecture so the rungs are well-founded.
The stdout seam already exists. Every text command writes through the OS's
OUTCH ($2009 SYS_PUTC), which already branches on REDIRF: 0 = console
(ACIA), 1 = append to a RAM capture buffer at RPTR, 2 = stream to an open
file (FPUTB). Adding a mode 3 = "draw into the active window" is the whole
idea — every command then renders in a window through the same seam it already
uses, unchanged.
The scrollback is the card list, not CPU RAM. The naïve worry — per-window
scrollback buffers (~250 B × 4 windows) in a machine with no spare RAM — is a
non-problem, because the kernel already replays each window's card list on
every repaint (wkd_cnt: if klist!=0 CLRUN klist — this is how SHAPES draws).
So mode 3 does not buffer text in RAM; it records MOVE3+TEXT into the
window's card list as bytes arrive. The card retains it; a repaint replays it;
persistence is free. Per-window state shrinks to a tiny cursor (col, row,
list-id) — a handful of bytes in a small kernel table, not a record blow-up.
Scrolling past the window bottom is the one hard case (card lists do not scroll);
v1 wraps and, on overflow, clears the list and restarts at the top (a simple
"screen-full then clear" terminal), with a real scroll a later refinement.
Control flow — the script-chain, so wdesk stays the client. The wall is
SYS_EXEC: it BECOMES the command, so control returns to the shell, not to
wdesk. Rather than move the desktop loop into the OS shell (which would undo the
kernel-lean/client-rich split we just built), wdesk chains through the OS's
existing script mode (SCRIPTM, the sh machinery): on TERM ENTER it (1)
points the sink at the TERM window (mode 3, cursor home), (2) writes a two-line
script — <cmd> then run /bin/wdesk.bin -o — and (3) hands the shell that
script and returns. The shell runs the command (its OUTCH bytes record into
the window's list) then re-execs wdesk, which resumes with the output already on
the card. wdesk stays the desktop driver; the OS gains only the sink. (Cost: the
screen shows the command run on the desktop, not live-in-window mid-run — output
appears when wdesk resumes. Acceptable for v1; true live rendering needs the
shell itself WM-aware, a later fork.)
The budget wall is the real prerequisite. Mode-3 code (record a glyph, wrap,
newline, clear-on-overflow) is ~80–120 B and MUST be OS-resident (it runs while
the command owns the TPA, so it cannot live in wdesk). The OS ends $5ED7, only
~41 B before the $5F00 tab-complete scratch. So the first rung frees room by
relocating that scratch (CMPPFX/CMPLCP/CMPDIR, three strings at $5F00)
down into the $6000 BIOS/FS scratch page (or folding them into existing
buffers), lifting the ceiling ~256 B. This is invasive (the completion code
names those addresses) and gated on the full suite + a tab-complete test.
Slice plan (each a shippable, tested rung):
- 15a — reclaim OS budget — DONE 2026-09-08. The tab-complete scratch strings
(CMPPFX/CMPLCP/CMPDIR) pinned the OS ceiling at $5F00. First packed to
the top of their page ($5F70, +112 B); then, when 15b's sink turned out to be
255 B (the 16-bit idiom is ~2× a first estimate — a MOVE3 is one opcode plus
three little-endian pairs), the whole page was needed, so the strings were moved
OUT of it to alias APBUF ($6800, the >> redirect-append buffer): the
two are disjoint in time — completion runs only in the interactive line editor,
the append buffer only during a redirect flush, and no program is loaded in
either case. The OS may now grow to $6000 (the full 256 B page). Safe by
construction and referenced only symbolically; os_complete_test passes with
the aliased buffers.
- 15b — the sink (mode 3) — DONE 2026-09-08. OUTCH gained REDIRF=3
(OUTWIN): each stdout byte is recorded into the target window's card list —
printable → TEXT 1 char (the card's TEXT auto-advances the pen, so no per-char
MOVE3), LF → drop a line + MOVE3 home, CR → MOVE3 home. SYS_WKSINK
($204E) arms it: A = window index → read the record's list id + height, home
the cursor near the top (y = h-29, y-up local), CLBEG the list, set
REDIRF=3; A = 255 disarms (CLEND, REDIRF=0). No wrap/scroll yet — long
lines and past-the-bottom output just clip. The whole thing is ~130 B of new
asm; OS ends $5FD6, 42 B under $6000. c_wsink_test arms the sink at a
window (content = card list 40), prints two lines, disarms, repaints — and the
text appears ONLY via the kernel's CLRUN of the list (recording draws nothing
live), proving it recorded into the list and persists.
- 15c-i — the arm survives the shell — DONE 2026-09-08. The open question was
real and had three answers, not one: the shell resets/repurposes REDIRF per
command in three places, all now taught about mode 3. (1) FLUSHRED (top of each
shell iteration) reset it to 0 — now it leaves REDIRF=3 armed (the client
disarms it, not the prompt). (2) DR_OUT treated any nonzero REDIRF as a
file redirect (it opened a write stream to REDNAME and forced REDIRF=2) — now
mode 3 passes through untouched, and the post-command close fires only for an
actual streamed file (REDIRF==2, was >=2). (3) GETLN's line echo went
through OUTCH, so with the sink armed the typed/script text would land in the
window — now it echoes to the raw console (CONOUT), which is a no-op in every
normal case (echo always runs at REDIRF=0). ~18 B of OS. c_wshell_test arms
the sink from a program, returns to the shell, runs the stock pwd, and
shows the window: pwd's output is in it. os_append (>/>>) and os_argv still
pass.
- 15c-ii — wdesk's TERM renders command output — DONE 2026-09-08. THE FEATURE
IS COMPLETE. Type a command in TERM, ENTER runs it, its output appears in the
window. term_run() finds the TERM window by title, arms the sink at it
(SYS_WKSINK), writes /TERM.SCR = <cmd>\nrun /bin/wdesk.bin -o, and hands it
to the shell (SYS_RUNSH, added as 15c-ii-a -- a program handing the shell a
script). The command's stdout records into TERM's card list (id 31); the script's
second line re-launches wdesk -o, which disarms the sink and repaints, so the
kernel's CLRUN shows the output. TERM's window opened with list=31 (the sink
target); term_body now draws only the input line (bottom of the body); the card
list is the scrollback. A THIRD script-echo path turned up during bring-up:
GL_SCRIPT (the sh/script-mode line reader) echoed through OUTCH, so the
script's own lines (pwd, run /bin/wdesk.bin -o) landed in the window -- routed
to the raw console like the interactive GETLN echo, so only real command output
shows. c_wtermout_test: boot into /WTERM, focus TERM, run pwd -> /WTERM
renders in the window (0 -> 88 px vs an empty TERM). The OS is now completely full
(ends $5FFF, 1 B under $6000) -- any further sink work needs more budget.
Known v1 edges: each command clears the window (CLBEG), no scroll/wrap, the
input line can smear on backspace (no per-keystroke FLOOD), and a GUI app typed
in TERM runs through the script chain rather than launching cleanly (launch apps
from the menu / FILES).
- 15d (later) — real scroll, and eventually a shell-WM path for live
mid-command rendering.
Risks / open questions¶
- Kernel event parsing in asm.
lib_ptr's SGR-mouse + arrow parsing is ~2 KB of C. In asm it is the biggest single piece; may warrant staying a small loaded-high C helper the kernel calls, if the budget allows. - Reduced app stack. RESOLVED (2026-09-07): with the kernel folded into the
OS image (below the TPA), GUI apps have the full ~37.9 KB TPA and the normal
CSTACKTOP($F800) — no per-app--cstacktop, same budget as any program. (The old$D800design gave apps only 28 KB.) - Kernel loading. RESOLVED (2026-09-07): there is no blob and no load step.
The kernel is
.included intop8xos.asmand reached via syscalls$2027..$2036, resident from boot. The standalone.org'd harness (os/wmkernel.asm) andwm_reside_testare retired — OS residency across launches is exercised by every remaining WM test.