Flat arrays, not trees
Every Space is a flat window list. Layouts are pure functions over that array — no tree surgery, ever.
KiwiDesk manages windows in flat arrays, not i3-style trees — fully Lua-configurable, with seven layouts to switch between. And it never disables SIP.
License ↗ · written in Swift and Lua · signed and notarized · macOS 14+, Apple silicon
🥝 Version 2.0.0“Tiling managers were always a nerd's toy. I wanted to make them intuitive for everyone – it should just work, like that.”
“I wanted a window manager that works with you — not one you have to tell how to work.”
Seventy seconds of KiwiDesk doing the thing: five messy windows tiled in one step, the scrolling layout, a window dragged onto the Space Bar, a pinned window that follows you, and one profile per macOS Desktop.
Watch on YouTube ↗Every feature, one clip each ↗Where it all began ↗
“Fair warning: you'll open windows on purpose, just to watch them snap into place.”
100% juice, no filler.
KiwiDesk is my go-to window manager. The developer is responsive, friendly, and has a clear vision for the app. And yet, KiwiDesk has so many options and is so flexible that it immediately replaced the more opinionated window managers I had.

KiwiDesk is the best tiling window manager on the Mac, hands down! The more I use it and the more its feature set grows, the less I find myself turning to Linux.

This is where people should start with macOS tiling managers. While I love Rift and Amethyst — had I known this existed, I would have never needed to go through the trial and error.
A flat, one-dimensional window model — and everything fast, scriptable, and safe that falls out of it.
Every Space is a flat window list. Layouts are pure functions over that array — no tree surgery, ever.
bsp, stack, scrolling (PaperWM), monocle, grid, track, and floating. Switch between them instantly.
Send a window to Desktop 3, switch to it, or bind a profile so a Desktop brings its own Spaces with it.
No kernel extension. Modal keybindings run through Carbon — no Input Monitoring permission, no keylogger.
Private OS symbols resolve at runtime and every tiling path has a public Accessibility fallback — an update can slow a fast path, never break the tiling.
Switch or merge tabs in Finder, Safari or Terminal and your layout holds. To a window manager every macOS tab is a separate window — where tiling usually breaks.
A sticky window follows you across every Space — or just the one screen it lives on. A mark on the window and a badge in the Space Bar show you which.
A sandboxed Lua 5.5 VM reads ~/.config/KiwiDesk/init.lua. A broken config can’t freeze your windows — a 500 ms watchdog guards it.
Script everything. Stream events to SketchyBar, JankyBorders, or your own tools over a socket.
Every control announces its name and its value under VoiceOver, and Settings can be driven entirely from the keyboard — with macOS’s Keyboard navigation on.
One display link per monitor, so mixed 60 / 120 Hz setups each animate at their own native cadence.
Every layout is a pure function over the same flat array — so switching is instant and predictable.
Binary space partitioning: each new window halves a pane.
A master zone beside a stack column.
Niri / PaperWM scrolling columns or rows.
Focused window maximized, rest behind.
Dynamic or rigid rows × columns.
Columns or rows; every resize has one true target.
The macOS default, left untouched.
Prefer text to sliders? Drop real Lua into ~/.config/KiwiDesk/init.lua and it takes over — layouts, gaps, keybindings, all as code, running in a sandboxed Lua 5.5 VM behind a 500 ms watchdog so a typo can never freeze your windows.
-- ~/.config/KiwiDesk/init.lua
KiwiDesk.set_gap_global(10)
KiwiDesk.set_mode("music", "floating")
-- one flat array per space, tidy by default
KiwiDesk.bind("cmd+alt+left", function()
KiwiDesk.focus("left")
end)Every action is a command. Bind them to keys, script them, or stream live events over a Unix socket into SketchyBar, JankyBorders, or your own tools.
“The day my window manager became scriptable, my desktop started running itself. I haven't dragged a window since.”
$ kiwidesk set_mode monocle
$ kiwidesk focus left
$ kiwidesk get_state
# stream live events (feed SketchyBar, your own tools…)
$ kiwidesk subscribe space_change“Even though I'm perfectly comfortable in the terminal, I got tired of having to constantly track container nesting just to arrange my windows the way I want. KiwiDesk keeps everything flat. No unnecessary overhead, no distractions: just pure focus on my projects.”
Prefer a package manager? One command, and the kiwidesk CLI lands on your PATH. Either way KiwiDesk keeps itself up to date from there.
Read the DocsThe signed, notarized disk image is the same app — after installing it that way you link the kiwidesk CLI onto your PATH yourself, which the CLI guide covers.
$ brew install --cask kiwicanopy/tap/kiwidesk
# the kiwidesk CLI lands on your PATHLicense ↗ · written in Swift and Lua · signed and notarized · macOS 14+, Apple silicon
$ git clone https://github.com/KiwiCanopy/KiwiDesk.git
$ cd KiwiDesk
$ swift build -c release
# for contributors — Homebrew is the easy pathDownload KiwiDesk, or install it with Homebrew — it’s the same signed build either way, and it keeps itself up to date from there.
License ↗ · written in Swift and Lua · signed and notarized · macOS 14+, Apple silicon
KiwiDesk's source is public — a star on GitHub helps other people find it.
“They say an apple a day — but the kiwi's got more vitamins and bigger plans... 🥝”