KN-86 KEC Lisp Runtime Architecture
1. Context — the inversion
Section titled “1. Context — the inversion”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
decklineprototype 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/fb0directly 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 §5term/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 nowrender.crather thanvendor/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 §5ui/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/fb0directly under thevideogroup (no Linux console PSF, nosetfont, notty1handoff). The nOSh binary is the same Fe-over-native-renderer program in both; only the surface backend differs (SDL3 on desktop,/dev/fb0on device). The libvterm/tvterm host-embed framing from this draft’s v0.1 is moot — we own the surface directly.
2. The layered architecture
Section titled “2. The layered architecture”┌───────────────────────────────────────────────────────────────────────┐│ 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.
3. The C/Fe line — the central decision
Section titled “3. The C/Fe line — the central decision”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).
| Subsystem | Today | Target | Why |
|---|---|---|---|
| Fe VM, arena, GC | C (vendor/fe) | C | The interpreter itself. |
Native framebuffer renderer (render.c) + the two-tier wrapper | C (cell_api.c, spike re-pointed at render.c per ADR-0036) | C | The 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) | C | AMBER (default) / WHITE / GREEN foreground-hue picker; persists to nosh-config.toml. |
| Event loop + input classifier | C (main_tb.c, input_classifier.c) | C | Realtime 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 coproc | C | 44.1 kHz realtime; off-loaded to Pico on device. |
| CIPHER cadence/timing (tick, decay, blink) | C (cipher.c) | C | Frame-timed; lives next to the loop. |
| CIPHER grammar + vocabulary + selection | C data (cipher.c) | Fe (cipher/) | It is data + policy; authored content. |
| Deck-state save serialization + integrity | C (deck.c, nosh_save.c) | C | Crash-safe block writes, checksum. |
| Economy ledger (credit/reputation mutation atomicity) | C (deck.c) | C primitive | Tamper/corruption boundary. |
| Economy policy (when/how much) | C | Fe (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 C | Logic in Fe; the persisted struct stays C-validated. |
| nEmacs, REPL | C hosts that fe_eval (nemacs.c, repl_*) | Fe (nemacs/, repl/) | Pure UI + editing over Fe data. |
| Bare-deck tabs, SYS utils, attract | C (bare_deck.c, attract.c) | Fe (deck/, attract/) | Screens. |
| Cartridge runtime + dispatch | C loader (cartridge.c) | C loader → Fe host shell | Loader/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.
4. The two-tier native-renderer surface
Section titled “4. The two-tier native-renderer surface”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-tickCarts 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 dimensionsThese 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.
5. The Fe library stack — what to build
Section titled “5. The Fe library stack — what to build”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.
C substrate (L1) — mostly exists
Section titled “C substrate (L1) — mostly exists”| Module | State |
|---|---|
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 loop | spike ✓ — 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.c | carve 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.
Fe libraries (L3) — the build list
Section titled “Fe libraries (L3) — the build list”| Lib | Purpose | Seeds (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 flow | mission-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) widget | micro key-bar, ink-ui status-bar |
cipher/ | CIPHER grammar + vocabulary + selection (cadence stays C) | cipher-voice.md |
attract/ | ambient/screensaver scenes, Deck-State-seeded | neo/astroterm/cbonsai |
cart-runtime/ | the cart host shell: load .kn86, hand the cart the cell-api tier only, drive its on-* lambdas | ADR-0006 |
lib/ | list/seq/string/format std-lib used by all of the above | mal/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 glyphs0x96–0x9D),fine-bar(horizontal progress bar with sub-cell precision via hbar glyphs0xA8–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.
6. Pseudo-Lisp — three worked examples
Section titled “6. Pseudo-Lisp — three worked examples”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):
| Axis | Code today | Canon / target | Drift task |
|---|---|---|---|
| Grid | types.h 80×25, SDL | 1024×600 surface (ADR-0036); 128×75 = 1× cell ceiling, 80×25 = 12×24 view | nOSh re-flow (tracked) |
| Display | SDL 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 desktop | re-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 7 | implement phosphor.c scheme switch; amend SYS-tab picker option set |
| Orchestrator | C | Fe (this doc) | port L3 surfaces C→Fe |
| FFI surface | 95 (SDL) / 15 (spike) | ~30 cart + system-render tier (per §4b) | build sys_render + merge |
| Cart load | .kn86 Fe + legacy dlopen | .kn86 Fe only | retire dlopen (Wave 5) |
| Mission templates | static C g_template_pool | Fe-evaluated (board/) | move to Fe |
Recommended order (each step shippable):
- 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), fixtypes.hto remove the legacy 80×25 constants. (Already a tracked task; everything here sits on top of it.) - Build
sys_render+ the per-context capability split (cart symbols vs system symbols) and therender/+ui/Fe libs. Theui/lib is the build payload from the UI Design Language draft §10. - 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.
- Retire legacy dlopen + the static template pool.
9. Open decisions (for Josh)
Section titled “9. Open decisions (for Josh)”- 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.
- 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.
- 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.
- 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/fb0on 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. - 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#D84810as the on-glass default 2026-06-13; operator review reverted to the house phosphor AMBER#E6A020on 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.