Keyboard
Spec hygiene (
CLAUDE.mdrule 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.
Layout
Section titled “Layout”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). deleterebound — in:nemacs-literal/:prompt-textscopes,deletemoves from the old*binding to BACK (L12).case-togglestays 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.”
Topology — split, master / slave, TRRS
Section titled “Topology — split, master / slave, TRRS”Per ADR-0031 §2:
| Property | Value |
|---|---|
| Halves | Two: LEFT (master) + RIGHT (slave). Each carries one KB2040 + 17 hotswap switch positions (15 main + 2 thumb) + one trackpoint. |
| Inter-half link | TRRS 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 = LEFT | Convention 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 Pi | Master 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-C | Used 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 wiring | Fixed 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.
Pointing — 2× trackpoint
Section titled “Pointing — 2× trackpoint”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-0035 —
cursor-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.
Accelerometer — LIS3DH on master, I²C1
Section titled “Accelerometer — LIS3DH on master, I²C1”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).
Sweep OLED — permanently skipped (v0.x)
Section titled “Sweep OLED — permanently skipped (v0.x)”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).
Construction
Section titled “Construction”Build pattern per ADR-0018 §1 (commodity parts) + ADR-0031 §1 (Sweep specifics):
| Element | Choice | Notes |
|---|---|---|
| PCB | holykeebs 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 tier | Soldered kit | SMD components pre-populated; switch-socket population + plate / case assembly remain ours. |
| Controllers | 2× Adafruit KB2040 (RP2040, USB-C, Pro Micro form factor) on custom low-profile 5 mm headers | One per half. Sea-Picro is the named fallback (ADR-0024). Order 1× spare KB2040 for trackpoint-solder insurance (ADR-0032 §1). |
| Switches | Kailh Choc v1, hot-swap | Specific switch family TBD via hotswap iteration; bring-up suggestion: Choc v1 brown (tactile, neutral). |
| Key spacing | Choc 18 × 17 mm | Not MX 19 × 19. |
| Keycaps | MBK low-profile (canonical) | Sculpted Choc documented as an operator-swap alternative, not v0.1 canonical. |
| Trackpoint | 2× holykeebs SK8707-01 module + red cap | One per half. See Pointing section above. |
| OLED | Skipped (permanent for v0.x) | See Sweep OLED section above. |
| Plates / case | Slim low-profile plate stack; 3D-printed case color-matched to the Pelican-1170 cyberdeck aesthetic | Specific stack confirmed at order time. ferris-sweep-v2-case.md is the current candidate case STL. |
| TRRS cable | Included in base kit | Inter-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.
Pin assignment — per half
Section titled “Pin assignment — per half”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:
| Half | Function | KB2040 silkscreen | RP2040 pin | Notes |
|---|---|---|---|---|
| LEFT (master) | Trackpoint PS/2 clock | D4 (silk: SDA) | GP4 | PS/2 clock over the holykeebs adapter — not I²C SDA in this configuration. |
| LEFT (master) | Trackpoint PS/2 data | D5 (silk: SCL) | GP5 | PS/2 data over the holykeebs adapter — not I²C SCL. |
| LEFT (master) | LIS3DH SDA | D6 | GP6 | I²C1 SDA — moved from I²C0 (D4/D5) by ADR-0032 §3. |
| LEFT (master) | LIS3DH SCL | D7 | GP7 | I²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 Pi | USB-C | — | Master is the USB host endpoint → internal hub → Pi. |
| RIGHT (slave) | Trackpoint PS/2 clock | D4 (silk: SDA) | GP4 | Same pinout as master. |
| RIGHT (slave) | Trackpoint PS/2 data | D5 (silk: SCL) | GP5 | Same pinout as master. |
| RIGHT (slave) | USB-C | USB-C | — | Flashing only; not connected to the Pi in operation. |
| Both | SWD | SWCLK / SWDIO | — | Test pads on the KB2040 PCB underside. |
Interface
Section titled “Interface”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.
| Signal | From | To | Notes |
|---|---|---|---|
| USB upstream | Master KB2040 (LEFT half) | Internal USB hub downstream port | Short USB pigtail. |
| USB upstream | Internal hub upstream | Pi Zero 2 W OTG | Wired pigtail, no external cable. |
| TRRS | Slave 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.
Why USB HID over a direct GPIO matrix
Section titled “Why USB HID over a direct GPIO matrix”Unchanged from the pre-Sweep build spec:
- GPIO header pin starvation against I2S and future peripherals.
- Userspace debounce / key-repeat / hold-detection already solved in stock QMK.
- Latency under Linux scheduling is bounded by USB enumeration, not by userspace scan loops.
- 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.
Firmware
Section titled “Firmware”QMK keymap source lives at firmware/kn86-keyboard/. Per ADR-0031 §4 + §F3 and ADR-0032 §4:
| File | Role |
|---|---|
keymap.c | The 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.h | Trackpoint pin map (D4/D5 PS/2 per half), LIS3DH I²C1 init (D6/D7), QMK matrix dimensions, debounce, USB descriptor strings, NKRO toggle. |
rules.mk | MCU = rp2040, BOOTLOADER = rp2040, split-keyboard enable, pointing_device_driver = ps2_mouse, LIS3DH driver enable. |
README.md | Per-file roles + the keyboards/handwired/kn86 → keyboards/ferris/sweep retarget note. |
- Target tree:
keyboards/ferris/sweep(existing QMK community keyboard). Master/slave handoff via the QMK split-keyboard subsystem on theserialdriver. - 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.crewrite + the QMKkeyboard.jsonselection 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.
Authoring boundary
Section titled “Authoring boundary”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.
Mechanical
Section titled “Mechanical”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.
Bring-up
Section titled “Bring-up”Per ADR-0031 §F7 + ADR-0032 §F5, and Stage 3 in build-specification.md §4:
- Receive the holykeebs Soldered kit (2× Sweep halves, 2× KB2040, 2× trackpoint module, TRRS cable) + spares.
- 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).
- Flash stock QMK with the 34-key Sweep
keymap.cper ADR-0031 §3.1 + the trackpoint/LIS3DH config per ADR-0032 §3–§4. - Install Choc v1 switches in the hotswap sockets; install MBK keycaps (blank in v0.1).
- Mount the internal USB hub IC; wire master USB-C → hub downstream, hub upstream → Pi OTG. Connect the TRRS link between halves.
- 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.
- Both halves enumerate over TRRS as one logical keyboard; all 34 positions report unique scancodes (
Sourcing
Section titled “Sourcing”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.
See also
Section titled “See also”processor.md— Pi Zero 2 W reads keyboard + trackpoint via USB HID + evdev.software/runtime/input-dispatch.md— logical key model, hold detection, TERM context dispatch.software/runtime/key-test-utility.md— Key Test runtime utility.enclosure.md— Pelican 1170 bezel insert (two-keyplate aperture + TRRS pass-through + 2× trackpoint cutouts).build-specification.md§4 Stage 3 — bring-up checklist.- ADR-0031 / ADR-0032 — the decisions this page documents.
- synthesis §4 — the worked-out 34-key layout + placement rationale.
firmware/kn86-keyboard/README.md— QMK keymap implementation notes.