Skip to content

Keyboard

Spec hygiene (CLAUDE.md rule 1). This document does not restate canonical values (key count, layout family, switch ecosystem, controller part, accelerometer host). Those live in CLAUDE.md’s Canonical Hardware Specification — Keys + Accelerometer rows. Any value inline that contradicts CLAUDE.md is a bug — fix it there, then here.


The KN-86’s input subsystem is a stock Ferris Sweep (David Barr design) sourced from holykeebs as a Soldered kit, with 2× trackpoint pointing devices (one per index finger) and the LIS3DH accelerometer hosted on the master half. It connects internally to the Pi Zero 2 W as a single USB HID device through the internal USB hub.

For the canonical key count, layout family, switch ecosystem, controller part, and accelerometer host, see CLAUDE.md Canonical Hardware Specification — Keys + Accelerometer rows. The decisions behind this build live in ADR-0031 (Sweep adoption, layout, split topology) and ADR-0032 (2× trackpoint, LIS3DH I²C re-pin, permanent OLED skip).

Why the Sweep over a custom-fabricated board: a shipping community split keyboard satisfies the KN-86’s input spec as commodity parts and removes the entire custom-PCB fab/plate/debounce risk surface. The full rationale + options-considered analysis is in ADR-0031 Context + Options Considered; the corpus-level argument is in synthesis §2 (L7) and §4.

The TERM key is context-sensitive — default function is the terminal surface, with CIPHER-LINE seed-capture and additional contextual bindings overlaid per surface. The keyboard delivers the raw TERM scancode; nOSh resolves the binding (ADR-0016 §9, software/runtime/input-dispatch.md). TERM lives on the right outer thumb (RT1) per ADR-0031 §3.1.


The worked-out 34-key base layer — which canonical function lands on which physical Sweep position, with per-key placement rationale, the SHIFT layer, and the Nokia multi-tap letter map — is in synthesis §4.2–§4.5 and ratified in ADR-0031 §3.1 (the authoritative QMK layer manifest with per-key QMK→KN-86 keycode mapping). Do not restate the grid here — those two documents are the source of truth; reproduce them, do not redraw.

Summary of the logical mapping (positions defined in ADR-0031 §3.1):

  • LEFT half carries the 14 Lisp primitives function block (legends per ADR-0022 §1: NIL / INFO / LAMBDA-printed-FN / CONS / LINK on top; APPLY / BACK / CDR / CAR / QUOTE on home — pinky→index inner reach, per the ADR-0031 §3.1 2026-06-21 home-row revision: CAR/CDR are the index+middle rest-and-rock pair, each nav verb on its own finger; SYS / EQ / ATOM on bottom plus 2 reserved-for-v2 spares), with EVAL on the inner-thumb (LT0) and LSHIFT on the outer-thumb (LT1).
  • RIGHT half carries the digit 3×3 (1-2-3 top, 4-5-6 home, 7-8-9 bottom on the inner three columns) preserving the Nokia digit-to-letter binding (2=ABC … 9=WXYZ) from ADR-0016 §6, plus , . / ; - punctuation primaries and ENT on the outer two columns, with 0 on the inner-thumb (RT0) and TERM on the outer-thumb (RT1).
  • SHIFT layer (LSHIFT held, QMK MO(L1)) delivers the shift secondaries — full ASCII printable set per ADR-0031 §3.1 / synthesis §4.4.

Decisions closed by the layout (all per ADR-0031):

  • Shift gesture closed — LSHIFT is a physical thumb key held as a momentary modifier (MO(L1)); no long-press timing tax, no chord. Closes ADR-0022 §Known Unknowns #1 (ADR-0031 §3.2).
  • delete rebound — in :nemacs-literal / :prompt-text scopes, delete moves from the old * binding to BACK (L12). case-toggle stays on / (R01). The context-polymorphism contract from ADR-0016 §3 + ADR-0022 §7 is preserved; the active scope label on Row 24 + CIPHER-LINE Row 1 advertises the live behavior (ADR-0031 §3.3).
  • Phone-shape topology relaxes; digit-to-letter binding survives — the literal 16-key phone numpad is gone, but the 1-9 digit 3×3 preserves the spatial relationship and the Nokia muscle memory (the binding that mattered) is intact (ADR-0031 §3.1, synthesis §4.6). Copy must say “phone-style digit-to-letter mapping,” not “phone-style numpad.”

Per ADR-0031 §2:

PropertyValue
HalvesTwo: LEFT (master) + RIGHT (slave). Each carries one KB2040 + 17 hotswap switch positions (15 main + 2 thumb) + one trackpoint.
Inter-half linkTRRS cable per Sweep convention. QMK split-keyboard serial transport carries matrix + pointing events from slave to master over the TRRS data line (typically GPIO1, fixed by the Sweep PCB).
Master = LEFTConvention from QMK split keyboards (Corne, Sweep, Lily58). The LIS3DH lives on master; the EVAL commit verb (LT0) lives on master — concentrating the keys nOSh dispatch cares about most on the master half avoids inter-half-RTT latency on EVAL.
USB to PiMaster half’s KB2040 USB-C → internal USB hub IC (ADR-0018 §5) → Pi Zero 2 W OTG. Single USB HID interface from Linux’s perspective.
Slave USB-CUsed only for flashing the slave KB2040 — not connected to the Pi during operation. The operator uses the master’s USB-C path for all normal use.
Matrix wiringFixed by the Sweep PCB. We do not author the matrix layout; we author the QMK keymap on top of the PCB’s matrix.

From QMK’s perspective the two physical halves are one logical keyboard: a single keymap source (LAYOUT_split_3x5_2(...)) covers all 34 keys, with master/slave handoff handled by the QMK split-keyboard subsystem. The device is not a split-ergo from the operator’s perspective in spirit — both halves seat into a unified 3D-printed bezel inside the Pelican 1170 shell — but the topology is an honest split (two halves, two MCUs, TRRS), not a split-PCB pretending to be unified.


Per ADR-0032 §1:

  • 2× holykeebs trackpoint modules — Sprintek SK8707-01 sensor + adapter PCB + red rubber cap, one per half, mounted between the alpha keys under each operator index finger. Operator-facing capability description in trackpoint-module.md.
  • Driver: stock QMK PS/2-mouse driver (pointing_device_driver = ps2_mouse), compiled for both halves; each half drives its own trackpoint over the PS/2 protocol on its KB2040’s D4/D5 pins (see Pin assignment below).
  • One cursor: the slave’s pointer events flow to the master over the TRRS link via QMK’s split-keyboard pointing-device transport; the master emits them on its USB HID interface alongside its own trackpoint events. From the Pi’s perspective there is one mouse cursor — either index finger can drive it. No second USB device, no separate evdev node beyond the standard mouse interface.
  • Click semantics (interim): QMK PS/2-mouse stock tap-vs-drag threshold (press-and-release the stem within ~150 ms → click; longer → drag). Final gesture deferred to firmware bring-up. Hard constraint: none of the four canonical thumb keys (LT0 EVAL, LT1 LSHIFT, RT0 0, RT1 TERM) is reassigned to mouse-click — click comes from the stem itself or a chord that sacrifices none of the four. Button #1 (primary) only in v0.1; right/middle-click deferred to v0.2.
  • cart-FFI: pointer state exposure to cart Lisp was deferred in ADR-0032 §5 and then opened in v0.1 by ADR-0035cursor-position, on-trackpoint-move, on-trackpoint-click, cursor-visible! land in the nOSh FFI surface (ADR-0005 Tier 1). The cursor is exposed in cell coordinates on the main 80×25 grid, clamped to content rows 1–23.
  • Soldering note: the trackpoint daughterboard is a delicate one-shot solder onto the KB2040 underside (“after this soldering it’ll become extremely hard to separate the two PCBs” — holykeebs). The order carries 1× spare KB2040 as build insurance and 4–6 spare red caps (caps wear faster than sensors). The trackpoint must be installed before the keyboard PCB is screwed into the case — the stem protrudes through the keyplate and alignment depends on case fit.

The LIS3DH lives on the master (LEFT) half’s KB2040 only, on I²C1 (KB2040 silkscreen D6/D7, RP2040 GP6/GP7) per ADR-0032 §3 — moved from the original I²C0 (D4/D5) assignment because the trackpoint’s PS/2 adapter now consumes D4/D5 on both halves. The INT1 line (originally reserved on D6) is released — v1 LIS3DH is polling-only at 25 Hz ODR.

For the sensor part, range, ODR, axis convention, motion-classification model, and the ambient CRT-glitch system it drives, see CLAUDE.md Canonical Hardware Specification — Accelerometer row, and ADR-0023.

Why master-half only: the sensor reports motion events to nOSh via a vendor-defined HID report on the master’s USB HID interface (ADR-0023 §6). Hosting it on the slave would force either routing motion events over TRRS (latency + bandwidth cost against ≤300 ms gesture windows) or enumerating the slave on the hub (breaking the single-USB-HID-interface invariant). One sensor on master is sufficient for the 4-bucket motion classification — the Pelican 1170 shell rigidly couples both halves’ inset-panel mounts, so a case-jostle propagates equally to both halves (ADR-0031 §5, ADR-0032 §3).


The Sweep PCB has an optional 128×32 SSD1306 mount slot. v0.x ships without it, permanently (ADR-0032 §2). The OLED mount and the trackpoint mount are mutually exclusive on the Sweep, and trackpoint wins on both halves. The CIPHER-LINE 256×64 SSD1322 (ADR-0015) is the authoritative — and only — auxiliary display; it covers status / modeline / palette / echo at higher fidelity than the Sweep’s small SSD1306 would. Re-introducing the Sweep OLED in any future revision requires a new ADR (ADR-0032 §2).


Build pattern per ADR-0018 §1 (commodity parts) + ADR-0031 §1 (Sweep specifics):

ElementChoiceNotes
PCBholykeebs Ferris Sweep pair, current hotswap revision (hotswap sockets + 1N4148 SMD diodes pre-populated)The modified-diode revision frees SDA/SCL from the matrix scan, which the trackpoint requires — already the holykeebs default.
Build tierSoldered kitSMD components pre-populated; switch-socket population + plate / case assembly remain ours.
Controllers2× Adafruit KB2040 (RP2040, USB-C, Pro Micro form factor) on custom low-profile 5 mm headersOne per half. Sea-Picro is the named fallback (ADR-0024). Order 1× spare KB2040 for trackpoint-solder insurance (ADR-0032 §1).
SwitchesKailh Choc v1, hot-swapSpecific switch family TBD via hotswap iteration; bring-up suggestion: Choc v1 brown (tactile, neutral).
Key spacingChoc 18 × 17 mmNot MX 19 × 19.
KeycapsMBK low-profile (canonical)Sculpted Choc documented as an operator-swap alternative, not v0.1 canonical.
Trackpoint2× holykeebs SK8707-01 module + red capOne per half. See Pointing section above.
OLEDSkipped (permanent for v0.x)See Sweep OLED section above.
Plates / caseSlim low-profile plate stack; 3D-printed case color-matched to the Pelican-1170 cyberdeck aestheticSpecific stack confirmed at order time. ferris-sweep-v2-case.md is the current candidate case STL.
TRRS cableIncluded in base kitInter-half link.

The full configured BOM checklist (every holykeebs order axis with the decided choice) is in holykeebs-buyers-guide.md §“KN-86 BOM checklist.” Confirm at order time that the shipped PCB is the hotswap (modified-diode) revision, not the older solder-direct revision.


Authoritative table in ADR-0032 §3 (which amends ADR-0031 §3). Matrix rows / cols / TRRS data are fixed by the Sweep PCB and not authored here; the KN-86-authored peripheral pins are:

HalfFunctionKB2040 silkscreenRP2040 pinNotes
LEFT (master)Trackpoint PS/2 clockD4 (silk: SDA)GP4PS/2 clock over the holykeebs adapter — not I²C SDA in this configuration.
LEFT (master)Trackpoint PS/2 dataD5 (silk: SCL)GP5PS/2 data over the holykeebs adapter — not I²C SCL.
LEFT (master)LIS3DH SDAD6GP6I²C1 SDA — moved from I²C0 (D4/D5) by ADR-0032 §3.
LEFT (master)LIS3DH SCLD7GP7I²C1 SCL — moved from I²C0 (D4/D5) by ADR-0032 §3.
LEFT (master)LIS3DH INT1(released)(released)Reservation released by ADR-0032 §3 — v1 is polling-only. v2 interrupt-driven motion would re-allocate (D8/GP8 is free).
LEFT (master)USB to PiUSB-CMaster is the USB host endpoint → internal hub → Pi.
RIGHT (slave)Trackpoint PS/2 clockD4 (silk: SDA)GP4Same pinout as master.
RIGHT (slave)Trackpoint PS/2 dataD5 (silk: SCL)GP5Same pinout as master.
RIGHT (slave)USB-CUSB-CFlashing only; not connected to the Pi in operation.
BothSWDSWCLK / SWDIOTest pads on the KB2040 PCB underside.

USB HID over USB 2.0 to the Pi via the internal USB hub IC (TUSB2036 / FE1.1s on the interior plate — see processor.md and ADR-0018 §5). The hub fans the Pi’s single OTG port out to the master KB2040 and the cartridge bridge IC (cartridge-interface.md). No externally routed USB cables.

SignalFromToNotes
USB upstreamMaster KB2040 (LEFT half)Internal USB hub downstream portShort USB pigtail.
USB upstreamInternal hub upstreamPi Zero 2 W OTGWired pigtail, no external cable.
TRRSSlave KB2040 (RIGHT half)Master KB2040 (LEFT half)QMK split-keyboard serial transport — matrix + pointing events from slave to master.

The Pi reads HID events via standard Linux evdev (/dev/input/event*) for the keyboard interface and the standard mouse interface for the merged trackpoint cursor. nOSh parses the keyboard events into the logical key model in software/runtime/input-dispatch.md.

Unchanged from the pre-Sweep build spec:

  1. GPIO header pin starvation against I2S and future peripherals.
  2. Userspace debounce / key-repeat / hold-detection already solved in stock QMK.
  3. Latency under Linux scheduling is bounded by USB enumeration, not by userspace scan loops.
  4. The mech-keeb ecosystem has solved every problem in our spec as commodity parts — the Sweep adoption (ADR-0031) takes this argument to its conclusion: PCB, hotswap, split topology, QMK firmware, HID enumeration, trackpoint integration, and keymap authoring all come from the community.

ADR-0011 “early-boot key-scan timing”: the attention gesture (SYS+LINK held at boot) cannot be detected by an early-boot GPIO scan because the keys are USB HID. The system-image-update gate waits for USB enumeration before scanning. Unaffected by the split topology — Linux still sees one keyboard interface.


QMK keymap source lives at firmware/kn86-keyboard/. Per ADR-0031 §4 + §F3 and ADR-0032 §4:

FileRole
keymap.cThe 34-key LAYOUT_split_3x5_2(...) keymap with the L0 BASE + L1 SHIFT layer manifest per ADR-0031 §3.1. Retargeted from the legacy handwired 31-key keymap; the old keymap is archived at _archive/firmware/kn86-keyboard-handwired-31key/.
config.hTrackpoint pin map (D4/D5 PS/2 per half), LIS3DH I²C1 init (D6/D7), QMK matrix dimensions, debounce, USB descriptor strings, NKRO toggle.
rules.mkMCU = rp2040, BOOTLOADER = rp2040, split-keyboard enable, pointing_device_driver = ps2_mouse, LIS3DH driver enable.
README.mdPer-file roles + the keyboards/handwired/kn86keyboards/ferris/sweep retarget note.
  • Target tree: keyboards/ferris/sweep (existing QMK community keyboard). Master/slave handoff via the QMK split-keyboard subsystem on the serial driver.
  • MCU / bootloader: rp2040 (both halves); drag-drop UF2 to the BOOTSEL volume.
  • USB: native RP2040 hardware Full Speed on master only; slave USB-C is flash-only.
  • Trackpoint: stock QMK PS/2-mouse driver on both halves; pointing events merged to one cursor over TRRS (ADR-0032 §4).
  • LIS3DH: unchanged driver behavior from ADR-0023 §5, re-pinned to I²C1; runs on master only; vendor HID report on the master’s USB HID interface.

The 34-key Sweep keymap.c rewrite + the QMK keyboard.json selection are tracked as ADR-0031 §F3 (keymap retarget) and ADR-0032 §F3 (trackpoint driver + LIS3DH I²C1 init), owned by Platform Engineering, blocked on the holykeebs hardware arriving.

Keyboard firmware stays dumb for the logical key surface: it delivers raw key-down / key-up events. LAMBDA hold, QUOTE bookmark slots, SYS hold abort, TERM context dispatch, hold detection, and macro replay remain nOSh-owned (ADR-0018 §6 doctrine, preserved). Two QMK firmware features are now used (where v0.1 previously used none): the SHIFT momentary layer (MO(L1), ADR-0031 §3.1) and the PS/2-mouse pointing-device driver (ADR-0032 §4) — both are stock QMK, authorized by their respective ADRs.


Both KB2040 controllers draw from USB bus power (5 V from the internal hub, regulated to 3.3 V on each controller); the slave is powered over the TRRS link from the master. No separate rail. The 2× trackpoint adds ~6.5 mA active / ~1.8 mA idle and the LIS3DH ~0.1 mA — within bring-up measurement noise against the CLAUDE.md Battery row envelope (ADR-0032 §6). Power topology lives in power.md.


Both Sweep halves seat into a 3D-printed bezel insert in the Pelican 1170 inset panel, above the primary display and the CIPHER-LINE OLED. The Pelican shell itself is not modified. Per ADR-0031 §Consequences + ADR-0032 §7, the bezel insert grows from the prior single-keyplate aperture to:

  • Two keyplate apertures (one per half),
  • A TRRS-cable pass-through between them,
  • 2× cutouts for the trackpoint stems to protrude through the keyplate between the alpha keys.

Bezel-insert re-design is tracked as ADR-0031 §F4 + ADR-0032 §F2 (Hardware-owned), designable in parallel from the holykeebs PCB dimensions + the Sprintek SK8707-01 datasheet. See enclosure.md.


Per ADR-0031 §F7 + ADR-0032 §F5, and Stage 3 in build-specification.md §4:

  1. Receive the holykeebs Soldered kit (2× Sweep halves, 2× KB2040, 2× trackpoint module, TRRS cable) + spares.
  2. Solder each trackpoint daughterboard onto its KB2040 underside (one-shot — use the spare KB2040 to absorb a failed join). Install the LIS3DH on the master half per §F2 (reflow on the Soldered-kit pass if holykeebs can, else ADA-2809 breakout on flying-lead I²C1).
  3. Flash stock QMK with the 34-key Sweep keymap.c per ADR-0031 §3.1 + the trackpoint/LIS3DH config per ADR-0032 §3–§4.
  4. Install Choc v1 switches in the hotswap sockets; install MBK keycaps (blank in v0.1).
  5. Mount the internal USB hub IC; wire master USB-C → hub downstream, hub upstream → Pi OTG. Connect the TRRS link between halves.
  6. Validate:
    • Both halves enumerate over TRRS as one logical keyboard; all 34 positions report unique scancodes (xxd /dev/input/event* / QMK tester).
    • Both trackpoints contribute to one cursor; click works (evtest).
    • LIS3DH is found on master I²C1; vendor HID report emits on /dev/hidraw*; the ambient CRT-glitch system drives correctly.

The configured order BOM is the holykeebs-buyers-guide.md §“KN-86 BOM checklist.” Order line items, decided:

  • Ferris Sweep PCB pair — black, current hotswap revision (hotswap sockets + 1N4148 SMD diodes pre-populated).
  • Build tier — Soldered kit.
  • 2× Adafruit KB2040 (~$8.95 ea) + 1× spare KB2040 (trackpoint-solder insurance). Sea-Picro named fallback.
  • 2× holykeebs trackpoint module (SK8707-01 + adapter PCB + red cap) — one per half + 4–6 spare red caps.
  • Controller mounting — custom low-profile 5 mm headers (saves 2.5 mm of internal stack height vs 7.5 mm machine headers).
  • Switches — Kailh Choc v1 hotswap (family TBD; bring-up suggestion Choc v1 brown).
  • Key spacing — Choc 18 × 17 mm.
  • Keycaps — MBK low-profile.
  • OLED — skip (permanent v0.x).
  • TRRS cable — included in base kit.
  • Plates / case — slim low-profile stack + 3D-printed case (or our own color-matched STL).
  • Internal USB 2.0 hub IC (TUSB2036 / FE1.1s / equivalent) + passives, and a short USB pigtail master → hub.

Suppliers: holykeebs (Sweep Soldered kit + trackpoint modules — one-stop), Adafruit / Amazon / AliExpress (spare KB2040, hub IC). The cross-references and trade-off notes for each axis are in holykeebs-buyers-guide.md. The custom-fab keyboard-PCB line from the prior build is retired — the Sweep PCB is fabricated by holykeebs.