Skip to content

KN-86 KEC Lisp Runtime Architecture

Today (the current code). The entire nOSh orchestrator is C. KEC Lisp is used only for cartridge bodies (.kn86 v2 Lisp source fe_eval’d through a C loader — tree-walked, no bytecode; see ADR-0004 2026-06-14 amendment) and for the content the REPL/nEmacs evaluate. C reaches Fe at exactly one seam — the FFI binder in runtime/src/nosh_lisp_bridge.c (95 bound primitives in the live SDL path). Mission board, economy, phase chain, deck state + save, CIPHER grammar, nEmacs, REPL host, bare deck, attract, SYS tools — all C.

Target (this doc, post-ADR-0036 reconciliation). Invert it: KEC Lisp authors the whole userland over the native framebuffer renderer; C shrinks to a substrate. The mission board, nEmacs, REPL, the bare-deck tabs, the deck utilities — all become Fe programs that drive the native-renderer wrapper, exactly the way carts already do via the cell-API tier. C keeps only what must stay C: the Fe VM, the native framebuffer renderer (render.c + phosphor.c), hardware I/O, the event loop, and a small set of integrity/timing-critical services. (As-drafted v0.1 named termbox2 as the substrate; ADR-0036 ratified the native renderer 2026-06-13.)

This is the same move ADR-0027 already started for carts (a closed cell API, the cl-termbox2 authoring shape without device authority) — extended up the stack to the system software itself, with system software getting a fuller, privileged tier of that same wrapper.

2026-06-13 reconciliation. This draft was written 2026-06-12 against ADR-0027’s termbox2 display layer. The on-glass session of 2026-06-13 against the production deckline prototype resolved the substrate question this draft posed (cl-termbox2-style wrapper vs. own renderer): ADR-0036 ratifies the KN-86 native framebuffer renderer that paints /dev/fb0 directly on device and an SDL3 RGB565 surface on desktop. The §3 C/Fe line in this draft was right and is unchanged — Fe authors the userland, C keeps the substrate. The §4b system-tier API and the §5 term/ library this draft described as cl-termbox2-shaped are re-pointed at the native renderer (the shape — clear, glyph, text, box, present, poll — is preserved; the backend is now render.c rather than vendor/termbox2). The cart-facing authoring shape from ADR-0027 (the 10-builtin cell API + 5 event callbacks, chrome reservation, half-block canvas, operator pre-emption) is preserved verbatim; cart authors see no change. The UI Design Language draft (2026-06-13) cashes out the §5 ui/ row.

One application. On desktop this is our own host app that paints into an SDL3 RGB565 surface SDL3 presents; on device it opens /dev/fb0 directly under the video group (no Linux console PSF, no setfont, no tty1 handoff). The nOSh binary is the same Fe-over-native-renderer program in both; only the surface backend differs (SDL3 on desktop, /dev/fb0 on device). The libvterm/tvterm host-embed framing from this draft’s v0.1 is moot — we own the surface directly.


┌───────────────────────────────────────────────────────────────────────┐
│ L0 HOST SURFACE │
│ desktop: SDL3 RGB565 surface (1024×600), SDL3 presents window │
│ device: /dev/fb0 direct (kiosk, video group, no console PSF) │
├───────────────────────────────────────────────────────────────────────┤
│ L1 C SUBSTRATE ("the kernel" — keep small) │
│ • Fe VM (vendor/fe) │
│ • KN-86 native framebuffer renderer (render.c — RGB565 to │
│ /dev/fb0 on device; SDL3 surface on desktop) per ADR-0036 │
│ • phosphor.c — AMBER/WHITE/GREEN scheme switch │
│ • event loop (poll input → classify → dispatch) │
│ • input classifier (31-key, hold, multi-tap, TERM ctx) │
│ • hardware I/O: audio (PSG/Pico coproc), OLED, save block device │
│ • integrity cores: deck-state save, economy ledger, CIPHER cadence │
│ • the bridge: bind() + GC-rooting (nosh_lisp_bridge.c) │
├───────────────────────────────────────────────────────────────────────┤
│ L2 Fe ⇄ NATIVE RENDERER WRAPPER (two tiers — §4) │
│ ┌─────────────────────────────┐ ┌──────────────────────────────┐ │
│ │ SYSTEM RENDER API (privileged) │ CART CELL API (constrained) │ │
│ │ native-renderer-shape: │ │ ADR-0027 preserved verbatim, │ │
│ │ render/clear, render/text, │ │ 10 builtins: │ │
│ │ render/glyph (any scale), │ │ cell-set/print, half-block, │ │
│ │ render/box, render/fill- │ │ cell-cols/rows, present/yield│ │
│ │ rect, render/bitmap, │ │ (backend re-pointed from │ │
│ │ render/present, render/poll │ │ termbox2 to render.c │ │
│ │ — all rows incl. chrome │ │ per ADR-0036) │ │
│ └─────────────────────────────┘ └──────────────────────────────┘ │
├───────────────────────────────────────────────────────────────────────┤
│ L3 Fe USERLAND (all software, authored in KEC Lisp) │
│ SYSTEM (system render tier): CARTS (cell-api tier): │
│ board/ mission board capability modules │
│ nemacs/ structural editor (ICE Breaker, Depthcharge…)│
│ repl/ Lisp REPL │
│ deck/ bare-deck tabs + SYS utils shared: │
│ cipher/ grammar + emission (cadence=C) ui/ component kit (§5,│
│ attract/ ambient + screensaver cashed out by │
│ ui-design-language)│
│ lib/ list/seq/string │
└───────────────────────────────────────────────────────────────────────┘

Everything in L3 is Fe. The boundary that matters is L1↔L2 (the C/Fe line, §3) and the split inside L2 (the two tiers, §4). The native renderer (per ADR-0036) replaces termbox2 at L1, but the L2 split — constrained cart cell-API tier vs. privileged system-render tier — is preserved unchanged.


The rule: Fe authors every screen and every flow; C keeps only what is unsafe, untimed, or unportable in Fe. Grounded in the current code (what is C today) and Fe’s real limits (single-threaded, mark-sweep GC over a fixed slab, 256 KB arena per context, instruction budget for sandboxing).

SubsystemTodayTargetWhy
Fe VM, arena, GCC (vendor/fe)CThe interpreter itself.
Native framebuffer renderer (render.c) + the two-tier wrapperC (cell_api.c, spike re-pointed at render.c per ADR-0036)CThe L2 seam; paints RGB565 to /dev/fb0 (device) or an SDL3 surface (desktop); owns integer-scaled glyph blits, box-drawing, half-block, compositing (drop shadow / dither scrim). The cart authoring shape from ADR-0027 is preserved verbatim — the cell-API surface is unchanged; only its backend changes from termbox2 to render.c.
Phosphor scheme switch (phosphor.c)new (per ADR-0036)CAMBER (default) / WHITE / GREEN foreground-hue picker; persists to nosh-config.toml.
Event loop + input classifierC (main_tb.c, input_classifier.c)CRealtime poll/classify; dispatches into Fe. Unchanged by ADR-0036 — the loop polls the input source (libinput on device, SDL3 events on desktop) regardless of the rendering backend.
Audio (PSG synth, I2S)C (psg.c/sound.c) + Pico coprocC44.1 kHz realtime; off-loaded to Pico on device.
CIPHER cadence/timing (tick, decay, blink)C (cipher.c)CFrame-timed; lives next to the loop.
CIPHER grammar + vocabulary + selectionC data (cipher.c)Fe (cipher/)It is data + policy; authored content.
Deck-state save serialization + integrityC (deck.c, nosh_save.c)CCrash-safe block writes, checksum.
Economy ledger (credit/reputation mutation atomicity)C (deck.c)C primitiveTamper/corruption boundary.
Economy policy (when/how much)CFe (board/, carts)Game design, not integrity.
Mission board (gen + UI)C (mission_board.c, nosh_mcg.c, static g_template_pool)Fe (board/)The spec already wants Fe-parsed templates.
Phase chain (FSM logic + UI)C (cartridge_fsm.c)Fe (board/) — state struct stays CLogic in Fe; the persisted struct stays C-validated.
nEmacs, REPLC hosts that fe_eval (nemacs.c, repl_*)Fe (nemacs/, repl/)Pure UI + editing over Fe data.
Bare-deck tabs, SYS utils, attractC (bare_deck.c, attract.c)Fe (deck/, attract/)Screens.
Cartridge runtime + dispatchC loader (cartridge.c)C loader → Fe host shellLoader/sandbox = C; the host UI = Fe.

Open fork (Josh): the table above is the Fe-userland, C-keeps-cores read. The alternative is Fe-maximal — push economy ledger / save / CIPHER cadence into Fe too, leaving C as literally just VM + native renderer + I/O + loop. Recommended against for v1 (save/economy are the tamper + corruption surface; Fe’s single-thread + GC make frame-timed cadence riskier), but it is your call. See §9.


ADR-0027 proved the constrained tier and explicitly rejected a 1:1 termbox binding for carts (Option B) — carts get the authoring shape, not device authority. ADR-0036 preserves that decision: the two-tier model survives the display-layer change verbatim. What changes is the underlying paint surface — the privileged tier exposes the native renderer’s primitives rather than a cl-termbox2 binding.

4a. Cart tier — the constrained cell API (exists today, preserved verbatim per ADR-0036)

Section titled “4a. Cart tier — the constrained cell API (exists today, preserved verbatim per ADR-0036)”

The closed 10 builtins from cell_api.c + 5 semantic-event callbacks. Carts see tokens, never backend encodings; chrome rows 0/74 are runtime-owned (out-of-region writes dropped + counted). Per ADR-0036 §“What ADR-0027 we keep,” the cell-API surface is preserved verbatim(cell-set col row ch fg bg) now compiles to blit_glyph(col*8, row*8, ch, 1, fg, bg) inside the native renderer rather than a tb_set_cell() call inside termbox2, but the cart author sees no difference. cell_api.c is still the cart-facing Fe binding; only its backend implementation changes from termbox2 to render.c.

(cell-set col row ch fg bg) (half-block-set x y on) present ← advisory
(cell-print col row fg bg str) (half-block-rect x y w h on) yield ← return to runtime
(cell-clear-cart-region) (half-block-clear)
(cell-cols) → 128 (cell-rows-usable) → 73 ; fg ∈ {phosphor, black}, bg ∈ {phosphor, black}
; cart defines lambdas: on-key on-multi-tap on-hold on-resize on-tick

Carts read the active phosphor scheme via (get-aesthetic-mode) → :amber | :white | :green (per ADR-0036’s amendment of ADR-0034). The cart’s fg/bg tokens (AMBER historically, now PHOSPHOR) bind to whichever hex the operator’s session is running.

4b. System tier — the privileged native-renderer wrapper (to build)

Section titled “4b. System tier — the privileged native-renderer wrapper (to build)”

The privileged surface ADR-0027 §Decision-5 reserved for system code. Per ADR-0036, the privileged tier is the native renderer’s primitive set — it composes at any integer scale (1×–N×) on the same 1024×600 surface the cart tier paints, plus the box-drawing, integer-scaled text, raw bitmap blits, and primitives for §10 compositing in the UI Design Language draft. Only L3 system code links it:

(render/clear) ; whole framebuffer (incl. chrome)
(render/text x y scale fg text) ; draw text at any integer scale
(render/glyph col row code scale fg bg) ; one glyph at scale
(render/fill-rect x y w h fg) ; solid rect (px coords)
(render/box cx cy cw ch single|double title?) ; box-drawing per UI design language
(render/bitmap x y bytes w h fg) ; arbitrary 1bpp blit (font extension hook)
(render/present) ; flush to /dev/fb0 (or SDL surface)
(render/poll) → event ; raw input event stream
(render/width) → 1024 (render/height) → 600 ; canonical surface dimensions

These are NOT cart-visible. Same VM, same bind() mechanism (§ grounding: fe_set(fe_symbol …, fe_cfunc …)), different symbol set loaded per context. A cart context never has render/* symbols bound; a system context has cell-API + render/*. That is the sandbox — capability by binding-set, enforced at context creation, not by runtime checks.

The compositing primitives the UI Design Language draft §8 specifies — drop shadow, dither scrim, modal compositing — bottom out in (render/fill-rect) and (render/bitmap). The box-drawing weights (single-line panels, double-line modals + focused panels) bottom out in (render/box). The integer type-size hierarchy (§5 of the UI Design Language draft) bottoms out in (render/text … scale …) and (render/glyph … scale …).

Open fork (Josh): CLOSED — ADR-0036 confirms two tiers (the constrained cart cell-API and the privileged system render API). See §9 #2.


This is the “start putting together the libraries” payload. Bold = new. The C substrate is mostly already there (spike); the Fe libraries are the green-field work.

ModuleState
vendor/kec-lisp (Fe kernel + Core)fetched at build ✓ — the one external dependency, cloned into the gitignored runtime/vendor/kec-lisp/ by tools/sync-kec-lisp.sh; never committed (ADR-0041)
render.c + render.h (native framebuffer renderer per ADR-0036)new — replaces vendor/termbox2. RGB565 paint to /dev/fb0 (device) or SDL3 surface (desktop); integer-scaled glyph blits over kn86_font[256 × 8]; box-drawing; half-block; compositing (drop shadow, dither scrim).
phosphor.c + phosphor.h (AMBER/WHITE/GREEN scheme switch per ADR-0036)new. Runtime-selectable foreground hue; persists to nosh-config.toml.
cell_api.c (cart tier)spike ✓ — the cart-facing Fe binding; calls into render.c rather than termbox2 per ADR-0036. Cart contract unchanged.
sys_render.c (system tier bind)new — §4b. Binds the render/* primitive set into the privileged Fe context.
input_classifier.c, main_tb.c loopspike ✓ — input poll path unchanged; the loop targets the native renderer’s (render/poll) rather than tb_peek_event.
nosh_lisp_bridge.c (bind + rooting)exists; extend with sys_render + the per-context capability split
deck_save.c, economy_ledger.c, cipher_cadence.ccarve the integrity cores out of today’s deck.c/cipher.c

The kn86-nosh-tb termbox2 spike is retained as a reference implementation of the constrained-cart authoring shape (useful for cross-checking the cell-API semantics during the native-renderer port), but is no longer on the path to production. The production binary is kn86-nosh linked against render.c.

LibPurposeSeeds (Batch 8)
render/Fe wrapper over the system render tier (4b). The cl-termbox2 shape originally proposed here is now historical context — the native-renderer surface (clear / text-at-scale / glyph-at-scale / fill-rect / box / bitmap / present / poll) is the actual Fe-facing API.ADR-0036 §“Decision,” seeded against the on-glass fb_restest.py validation suite
ui/the component kit — specified in full by the UI Design Language draft §10. Component roster pinned below.see below; the synthesis is now ui-design-language.md §1–§10
board/mission board: template eval (Fe, replacing g_template_pool), gen via lfsr-*, the board screen, phase flowmission-control.md
nemacs/structural editor over Fe cons-cells (a tree is an s-expression browser)hackernews-TUI tree, bookokrat
repl/REPL surface + history (mcfly-style context ranking)mcfly
deck/bare-deck tabs (STATUS/LAMBDA/LINK/SYS/MISSIONS), deck-state accessors, SYS utils, the (draw-keyboard) widgetmicro key-bar, ink-ui status-bar
cipher/CIPHER grammar + vocabulary + selection (cadence stays C)cipher-voice.md
attract/ambient/screensaver scenes, Deck-State-seededneo/astroterm/cbonsai
cart-runtime/the cart host shell: load .kn86, hand the cart the cell-api tier only, drive its on-* lambdasADR-0006
lib/list/seq/string/format std-lib used by all of the abovemal/build-your-own-lisp

ui/ component kit — the UI Design Language draft §10 specifies the full component roster, signatures, and the single-color discipline (glyph = identity, inversion = selection, density = magnitude, plus border weight + leading-glyph column + blink as orthogonal attention channels). The components the design language doc spec’d:

  • Chrome: status-bar (Row 0, scale 2, inverted, runtime-owned), action-bar (Row 74, scale 2, inverted, runtime-owned)
  • Frames: panel / box (single-line bordered region, optional title cutout), cbox (raw box-drawing primitive with single/double weight selection), modal (drop shadow + double-line cbox + black interior fill), popup (modal anchored to a cursor), palette (centered command-palette modal)
  • Lists / trees / tables: list (vertical scrolling, selected row inverted, leading-glyph column), tree (collapsible / glyphs — the s-expression browser surface), table (pinned header row, frozen leftmost columns, typed-column header glyphs)
  • Data display: sparkline (logradar recipe — 24 buckets, 2-min window, vbar glyphs 0x96–0x9D), fine-bar (horizontal progress bar with sub-cell precision via hbar glyphs 0xA8–0xAE)
  • Navigation + input: tab-bar (numbered 1–5, selected inverted), dial + slider (continuous-control widgets), cycler (single-row cycle through a small enum — the SYS-tab aesthetic-picker primitive), headline (big-glyph at scale 4–5)
  • Compositing: scrim (dither scrim per §8.1 of the design language doc), shadow (1-cell drop shadow), select-row (invert a row span), reveal (ADR-0033 transition primitive)

The full signatures, the four-channel rule, the box-drawing primitive contract (cbox with title-cutout pattern), the §7 four canonical layouts (L1–L4), the §8.3 compositing primitives (modal/popup/palette), and the §9 overlay patterns (command palette, IntelliSense completion, dialog) all live in the UI Design Language draft. That doc is the authoritative ui/ specification; this row is the index.


Illustrative Fe; names track the libs above. Not final signatures.

(a) A system screen — the mission board (system tier)

Section titled “(a) A system screen — the mission board (system tier)”
(require 'render)(require 'ui)(require 'deck)(require 'board)
(define (board/render st)
(render/clear)
(ui/status-bar 0 (deck/handle st) (deck/credits st) "MISSIONS") ; Row 0 chrome
(ui/panel 1 1 126 71 'heavy "CONTRACT BOARD")
(let loop ((rows (board/contracts st)) (y 3))
(when (pair? rows)
(let ((c (car rows)))
(ui/list-row 3 y 120
(board/title c)
(ui/sparkline (board/risk-curve c)) ; logradar recipe
(if (board/selected? st c) 'invert 'normal)))
(loop (cdr rows) (+ y 1))))
(ui/headline 80 4 (mission/countdown st) 4) ; scale-4 timer (ui-design-language §5.1)
(ui/action-bar 74 '(("EVAL" . accept) ("CDR" . next) ("BACK" . exit))) ; Row 74 chrome
(render/present))
(define (board/on-key st k) ; system context: full key stream
(cond ((key= k 'EVAL) (board/accept-selected st) (phase/advance st))
((key= k 'CDR) (board/move-cursor st +1))
((key= k 'BACK) (deck/goto st 'bare-deck))
(else st)))
(deck/register-screen 'mission-board board/render board/on-key)

(b) A deck util — the SYS aesthetic picker (system tier, short)

Section titled “(b) A deck util — the SYS aesthetic picker (system tier, short)”
(define (sys/aesthetic-render st)
(render/clear)
(ui/status-bar 0 (deck/handle st) (deck/credits st) "SYS · AESTHETIC")
(ui/cycler 4 10 "MODE" (deck/aesthetic st) '(AMBER WHITE GREEN)) ; ADR-0036 phosphor roster
(render/present))
(define (sys/aesthetic-on-key st k)
(if (key= k 'TERM) (deck/cycle-aesthetic! st) st)) ; persists to nosh-config.toml

(c) A cart — constrained cell-api tier (the sandbox boundary)

Section titled “(c) A cart — constrained cell-api tier (the sandbox boundary)”
;; A cart has NO render/* symbols. Only cell-* / half-block-* / present / yield.
;; Per ADR-0036, the cart cell-API surface is preserved verbatim from ADR-0027;
;; the foreground token PHOSPHOR binds to whichever AMBER/WHITE/GREEN hex the
;; operator's session is running.
(define snake '())
(define (on-tick) ; cart lambda, runtime-driven
(set! snake (snake-step snake))
(cell-clear-cart-region) ; rows 1–73 only; cannot clear chrome
(for-each (lambda (p) (cell-set (car p) (cdr p) ?# 'PHOSPHOR 'BLACK)) snake)
(present))
(define (on-key k) (set! dir (key->dir k)))

The only difference between (a) and (c) is the symbol set the context was created with. Same VM, same loop, same dispatch — capability is the binding set.


7. Screen-by-screen spec format (feeds the workbench)

Section titled “7. Screen-by-screen spec format (feeds the workbench)”

Superseded by the UI Design Language draft §11. The v0.1 sketch this section held has been expanded into a full schema in the design-language doc — surface (system | cart) + layout (L1–L4 or custom rectangles per the design language §7) + phosphor (inherits | locked) + overlays (palette / popup / dialog per §9 of the design language) + components (every name binds to a §10 primitive) + state.reads / state.writes + handlers.on-key / handlers.on-tick + transitions. The mission-board worked example from this draft’s v0.1 is reproduced as a fully-elaborated spec at ui-design-language.md §11.2.

The workbench owns the per-screen authoring loop; the UI Design Language draft §11 fixes the schema that the workbench edits and emits, so every screen compiles against the same Fe libraries (render/ + ui/) this doc describes in §4 and §5. The schema’s components field names §10 primitives; the schema’s layout field references the §7 canonical layouts; the schema’s overlays field references the §9 overlay patterns; the schema’s handlers.on-key field uses the Sweep key symbols from ADR-0031 §3.1.


8. Migration + the spec-to-code drift baseline

Section titled “8. Migration + the spec-to-code drift baseline”

The engineering agent’s drift audit starts from this table (current code vs canon/target):

AxisCode todayCanon / targetDrift task
Gridtypes.h 80×25, SDL1024×600 surface (ADR-0036); 128×75 = 1× cell ceiling, 80×25 = 12×24 viewnOSh re-flow (tracked)
DisplaySDL kn86emu (full, live) + termbox2 kn86-nosh-tb (partial spike, reference impl)KN-86 native renderer (per ADR-0036) — /dev/fb0 on device, SDL3 RGB565 surface on desktopre-flow C carts onto native renderer, retire SDL + spike paths
Phosphor color#E6A020 amber (canonical)AMBER #E6A020 (canonical default) + WHITE / GREEN selectable per ADR-0036 §“Decision” item 7implement phosphor.c scheme switch; amend SYS-tab picker option set
OrchestratorCFe (this doc)port L3 surfaces C→Fe
FFI surface95 (SDL) / 15 (spike)~30 cart + system-render tier (per §4b)build sys_render + merge
Cart load.kn86 Fe + legacy dlopen.kn86 Fe onlyretire dlopen (Wave 5)
Mission templatesstatic C g_template_poolFe-evaluated (board/)move to Fe

Recommended order (each step shippable):

  1. Finish the nOSh re-flow onto the native renderer — implement render.c + phosphor.c, retire the SDL display path, retire the termbox2 spike path (preserved as reference but not on the production trunk), fix types.h to remove the legacy 80×25 constants. (Already a tracked task; everything here sits on top of it.)
  2. Build sys_render + the per-context capability split (cart symbols vs system symbols) and the render/ + ui/ Fe libs. The ui/ lib is the build payload from the UI Design Language draft §10.
  3. Port surfaces C→Fe, simplest first: a SYS util → bare-deck tabs → REPL → nEmacs → mission board. Each port deletes its C file and adds a Fe module; the drift table shrinks by one row per port. Each ported screen is specified against the UI Design Language draft §11 screen-spec schema.
  4. Retire legacy dlopen + the static template pool.

  1. C/Fe line degree (§3) — OPEN. Fe-userland, C-keeps-cores (recommended) vs Fe-maximal. Affects whether economy ledger / save / CIPHER cadence are C or Fe. ADR-0036 did not touch this axis; the §3 table’s recommendation stands until Josh locks it.
  2. Cart sandbox (§4) — CLOSED by ADR-0036. Two tiers are confirmed: the constrained cart cell-API (preserved verbatim from ADR-0027) and the privileged system render tier (the native renderer’s primitives, per §4b). Capability is by binding-set at context creation. ADR-0036 §“What ADR-0027 we keep” explicitly preserves the two-tier model.
  3. CIPHER split — OPEN. Grammar/vocab → Fe, cadence → C (recommended). Confirm the seam. ADR-0036 did not touch this; ADR-0015 (CIPHER-LINE OLED separate render path) is unaffected.
  4. Host embed (L0/§7) — PARTIALLY RESOLVED by ADR-0036. The host is the native renderer painting to either /dev/fb0 (device) or an SDL3 RGB565 surface (desktop); the libvterm-app-vs-thin-widget question is moot because we own the surface directly. Resolves to: native renderer with two output backends (/dev/fb0 on device, SDL3 on desktop). Still open: does the workbench’s live-preview path embed a copy of the native renderer (statically linked, painting into a workbench-owned SDL3 surface), or does the workbench render screens to PNG / RGB565 dump files and display them as images? The first matches production paint paths exactly; the second is simpler to integrate into a browser-based workbench but introduces a second renderer pass-through.
  5. ADR-0034 aesthetic modes — CLOSED by ADR-0036. The roster locks as AMBER (default) / WHITE / GREEN — three foreground phosphor colors selectable per session, persisted to nosh-config.toml. (get-aesthetic-mode) return values become :amber / :white / :green. (ADR-0036 trialed EMBER #D84810 as the on-glass default 2026-06-13; operator review reverted to the house phosphor AMBER #E6A020 on 2026-06-17 — AMBER is the canonical default mode.) CIPHER-LINE cadence and scanline/overlay treatments are preserved (ADR-0034 §4.2/§4.3 — unaffected by ADR-0036).

Once #1 and #3 are locked, this doc becomes an ADR and the §5 library list becomes the build backlog.