
Who
I wanted niri's scrollable tiling on the Mac without living inside Hammerspoon.
YaLTeR's niri is a Wayland compositor: windows live in columns on an infinite horizontal strip; you scroll the strip like a document; opening a window does not crush the ones you already have. PaperWM.spoon already brings that idea to macOS in Lua on Hammerspoon. I wanted the same paradigm as a native Swift daemon with Accessibility APIs, spring animations, and a yabai-shaped IPC CLI so skhd can drive it.
If you have ever rewritten a compositor concept as a weekend Accessibility prototype and then left an autopsy in the repo for future-you, this is that diary.
What
I built niri-macos, SPM package niri-macos, version 0.1.0 (niri-macos --version), public under michaelmonetized/niri-macos. Platforms: macOS 13+. Zero external Swift packages. Products: library NiriCore, daemon niri-macos, CLI niri-msg.
Stack from the tree: AppKit + CoreGraphics + QuartzCore, AXObserver / AXUIElement for event-driven window tracking, CGWindowList enumeration, CVDisplayLink 60fps spring animation, CGEventTap gestures, Unix socket IPC at /tmp/niri-macos.sock with JSON commands. Config is JSON via ConfigManager at ~/.config/niri-macos/config.json (gaps, outer gaps, preset widths, spring params, scroll thresholds, windowRules Codable). Hotkeys stay external: skhd bindings documented in README and HOTKEYS.md. Gestures: Cmd+Shift+scroll (focus window), Cmd+scroll (workspace), 3-finger swipe (free scroll with momentum).

Surfaces that exist: horizontal layout engine (LayoutEngine.swift ~44KB), consume/expel column stacking, center/maximize/preset widths (33/50/66/100%), dynamic workspaces (up/down/create above/below), split groups (horizontal/vertical/quad), multi-monitor isolation (active monitor follows mouse), menubar operations, niri-msg status / list-windows / quit. Tests: 112 func test* under NiriCoreTests (layout, types, IPC). CI: GitHub Actions on macos-14 (build, test, release build). HEAD d21a739. Four commits. ~226KB of Swift.
README still marks Planned: focus ring overlay, window-rule enforcement (structs parse; sitrep says not applied), overview mode, sketchybar integration, Homebrew formula, launchd plist. PLAN.md still dreams of KDL like upstream niri; the shipped parser is JSON.

AUTOPSY.md (dated 2026-02-09) is the scar: it calls the early tree a 3,672-line prototype with two commits, zero tests, seven singletons, hardcoded gaps, and a README that was aspirational fiction. It also credits real spring physics, a thoughtful IPC command set, and clean ColumnWidth modeling. sitrep.md at the same era (updated for the refactor) says FUNCTIONAL: 112 passing tests, JSON config, protocol-based DI, main-thread layout serialization. The June 22 nightly commits are where that contradiction resolves in git history.
Where
Code: github.com/michaelmonetized/niri-macos, public. No hosted demo. Run locally: swift build -c release, put niri-macos on your PATH, grant Accessibility, start the daemon, drive it with niri-msg / skhd. Socket default /tmp/niri-macos.sock. Log default /tmp/niri-macos.log.
When
- 2026-02-06.
640d314feat: implement niri scrolling layout paradigm for macOS (initial README/PLAN + core sources). - 2026-02-08.
37f34adfix that is really a sequel: multi-monitor isolation, discrete scroll, workspace creation, split groups, animation/gestures/AX observer (+2391/−132). AUTOPSY calls the message an undersell. - 2026-02-09. AUTOPSY.md examination date; sitrep claims FUNCTIONAL + 112 tests (landed in tree with the later nightly push).
- 2026-06-22. GitHub repo
created_at; twonightlycommits (f3b1d77, HEADd21a739) ship NiriCore extraction, ConfigManager, full test suite, workflow, AUTOPSY in-tree, hustlemc/uncap crumbs. Last push2026-06-22T22:20:39Z.

Why
I use macOS and I still want niri's rule: new windows append; existing frames stay; scroll the strip; isolate per monitor. Hammerspoon is fine. I wanted direct APIs, spring physics I own, and niri-msg that feels like talking to yabai while the layout model is niri's.
I also wanted the honesty layer. Shipping AUTOPSY.md next to a polished README is the point: document the Jenga tower, then answer it with tests and a library boundary instead of deleting the roast.
Engagement Q
Would you rather run scrollable tiling as native Swift + Accessibility + skhd, or stay on PaperWM.spoon and keep the Lua runtime, and what would make you trust a 0.1.0 WM with four commits and 112 tests?
