Initial import: chezmoi source for CachyOS + Umbriel + Noctalia

Imported from prdlk/dotfiles master (efdd827). Drops the niri, Hyprland/Omarchy,
macOS, and Blume docs-site layers; docs/ is plain Markdown.
This commit is contained in:
Prad Nukala committed 2026-11-02 09:14:11 -05:00
commit ee355bcfd5
152 files changed
+11564

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
# Desktop
The desktop layer on CachyOS: the Umbriel compositor, the Noctalia shell, fontconfig, and default applications.
> [!NOTE]
> **Role gating**
>
> `.chezmoiignore.tmpl` skips the desktop layer unless the machine runs Linux **and** its role is `desktop` or `laptop`. The gated targets are `~/.config/umbriel`, `~/.config/noctalia`, `~/.config/fontconfig`, `~/.config/mimeapps.list`, `~/.config/xdg-terminals.list`, `~/.config/systemd`, `~/.local/bin/agent-root`, `~/.local/bin/kitty-day-save`, `~/.local/bin/umbriel-launch`, `~/.local/bin/umbriel-smart-move`, `~/.local/bin/umbriel-float-square`, `~/.local/bin/cp-appid`, and `~/.local/bin/projects-sync`. On the `server` role these are not applied.
The session is [Umbriel](https://docs.noctalia.dev/umbriel/), Noctalia's scrolling compositor, with Noctalia as the only session process: it provides the bar, launcher, clipboard history, notifications, polkit agent, and OSD.
| Page | Covers |
| --- | --- |
| [Umbriel](umbriel.md) | `~/.config/umbriel` (session, layout, outputs, rules, scratchpads, binds), `umbriel-launch`, `umbriel-smart-move`, and `umbriel-float-square` |
| [Fonts and default apps](fonts-and-apps.md) | `~/.config/fontconfig/fonts.conf`, `~/.config/mimeapps.list`, the Victor Mono Nerd Font packages |
The Noctalia config itself (`~/.config/noctalia`) is the [prdlk/noctalia](https://github.com/prdlk/noctalia) external, see [externals](../chezmoi/externals-and-ignore.md#chezmoiexternals).
## Packages
`.chezmoidata/packages.yaml` declares the desktop packages under `packages.arch.desktop`. `.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl` installs them only when the role is `desktop` or `laptop`:
| Source | Packages |
| --- | --- |
| pacman | `noctalia` (the CachyOS build where that repo is configured, else `extra`), `polkit`, `xdg-user-dirs`, `xdg-terminal-exec`, Wayland utilities (`wl-clipboard`, `cliphist`, `wtype`, `ydotool`, `grim`, `slurp`, `pamixer`, `brightnessctl`, `libnotify`), the bound apps (`nautilus`, `imv`, `mpv`, `evince`, `chromium`, `obsidian`), and strata's runtime deps |
| AUR via `yay`/`paru` (a sync repo wins when it has the name) | `tldraw-offline-bin`, `bibata-cursor-translucent`, `umbriel-git` (with `xdg-desktop-portal-umbriel-git`), `herdr-bin`, `voxtype-bin`, and the desktop apps `beeper-bin`, `fastmail`, `1password`, `brave-origin-bin`, `claude-desktop`, `spotify` |
AUR names that an installed package already provides are skipped; with no `yay` or `paru` the script bootstraps `yay` first. strata, the default file manager, comes from its own installer in [15-tools](../chezmoi/scripts.md#15-tools). See [chezmoi scripts](../chezmoi/scripts.md) for the full install flow and [packages.yaml](../chezmoi/data.md#packagesyaml) for the complete lists.
## Thunderbolt eGPU (compute only)
The RTX 5060 Ti in a USB4 enclosure (Minisforum `TBGAA`, bolt policy `iommu`) is for CUDA only: AI models, never displays or rendering. Every display hangs off the Radeon 8060S iGPU (PCI `c4:00.0`). Packages: `linux-cachyos-nvidia-open`, `nvidia-utils`, `cuda`, `opencl-nvidia`. Nothing in this section is managed by chezmoi except the session environment.
| File | Setting | Why |
| --- | --- | --- |
| `/etc/default/limine` | no `pci=nommconf`, no `pcie_aspm=off`; `pcie_aspm.policy=performance` instead | The first two make Linux skip the PCIe `_OSC` control request (`not requesting OS control; OS requires [ExtendedConfig ASPM …]`). Then `pciehp` never binds the USB4 bridges `00:01.1`/`00:01.2`, and the enclosure authorizes while the GPU never shows up in `lspci`. `pcie_aspm.policy=performance` disables ASPM without that side effect. Run `limine-update` after editing. |
| `/etc/modprobe.d/nvidia-egpu.conf` | `install nvidia_drm /bin/true`, `install nvidia_modeset /bin/true`, `NVreg_DynamicPowerManagement=0x00`, `NVreg_PreserveVideoMemoryAllocations=0` | Without `nvidia_drm` there is no `/dev/dri` node for the eGPU, so no compositor, GBM, or VA-API driver can open it. CUDA needs only `nvidia` and `nvidia_uvm`. `nvidia-suspend.service` is not enabled, and with `PreserveVideoMemoryAllocations=1` suspend fails while the eGPU is bound. |
| `/etc/modprobe.d/thunderbolt-egpu.conf` | `options thunderbolt host_reset=0 clx=0` | `host_reset=0` keeps the firmware-built PCIe tunnel at boot; with the default reset the tunnel drops while `nvidia` initialises the card (Xid 79, GPU stuck until reboot). `clx=0` keeps the USB4 lanes out of CL1/CL2 low-power states. |
| `/etc/systemd/system/nvidia-egpu-powercap.service`, `/etc/udev/rules.d/62-nvidia-egpu-powercap.rules` | `nvidia-smi -pm 1 -pl 150 -lgc 210,1800` when the `nvidia` module loads | Caps the card at 150 W / 1800 MHz before anything can load it. |
| `/etc/udev/rules.d/61-nvidia-compute.rules` | `nvidia-modprobe -c0 -u` when the `nvidia` module loads | `nvidia-utils`' own rule creates `/dev/nvidia*` when `nvidia_drm` loads, and that module never loads here. |
| no `/etc/modules-load.d` entry | none | udev loads `nvidia` by modalias when the GPU reaches the bus, at boot or on hotplug. |
`nouveau` is blacklisted by `nvidia-utils` (`/usr/lib/modprobe.d/nvidia-utils.conf`). Without that blacklist, nouveau binds the card, the NVIDIA driver reports `GPU … is already bound to nouveau`, and a link drop deadlocks `pciehp` in nouveau's GSP teardown.
Session side: `conf.d/10-env.fish` sets `__EGL_VENDOR_LIBRARY_FILENAMES` (Mesa) and `VK_DRIVER_FILES` (RADV), see [fish](../shell/fish.md#10-envfish). Umbriel starts through a fish login shell, so the compositor, Noctalia, and every app inherit them. Without them, glvnd and the Vulkan loader load the NVIDIA vendor libraries into every process, and those processes hold `/dev/nvidiactl`.
Never expose `nvidia_icd.json` to LM Studio. When its engine survey reaches the eGPU through NVIDIA's Vulkan driver, the card falls off the bus (`Xid 79`) and the machine hard-resets. The survey runs when the app starts and when the `llmster` daemon starts, and any `lms` command starts that daemon.
Check: `nvidia-smi` lists the card, and `fuser -v /dev/nvidia*` shows only CUDA processes. A short CUDA kernel (vector add) runs correctly.
### Status: unusable under load on the Flow Z13 (GZ302EA, BIOS 311)
The moment a model starts inference on the eGPU, the platform hard-resets with `x86/amd: Previous system reset reason [0x08000800]: an uncorrected error caused a data fabric sync flood event`, no Xid, no log tail. Firmware grants no AER/DPC to the OS, so a tunnel fault under load becomes a full reset. Everything above was tested one variable at a time on 2026-10-17 and none of it changed the outcome: CUDA or Vulkan engine, model size (27B and 12B), both USB4 ports, dock wiring per the DEG2 manual on a 650 W PSU, ASPM off, `clx=0`, 150 W power cap, KMS loaded or not, and the previous OS install with stock NVIDIA config. The same models run fine on the iGPU with the dock unplugged, so the fault is the Z13's USB4 PCIe path under GPU load, not the SoC alone. Other GZ302EA owners report the same reset code under sustained load ([Level1Techs](https://forum.level1techs.com/t/strix-halo-hard-power-off-under-sustained-inference-load-rog-flow-z13-gz302ea-instrumented-root-cause-hunt-ec-cooling-gated-power-cut-a-data-fabric-sync-flood-can-framework-desktop-other-strix-halo-owners-try-to-repro/252607)) and eGPU trouble on this platform ([ROG forum](https://rog-forum.asus.com/t5/rog-flow-series/gz302ea-bios-311-tb4-egpu-permanently-fails-on-linux-after/td-p/1146714)). Untested: a shorter certified 40 Gbps cable, the same dock and card on another host, Windows. LLM work runs on the 8060S (Vulkan/ROCm, unified memory) until one of those changes the picture.
+98
View File
@@ -0,0 +1,98 @@
# Fonts and default apps
Fontconfig monospace override to Victor Mono Nerd Font, the Nerd Font packages, and the XDG default-application table.
Two small files set system-wide defaults: `fonts.conf` picks the monospace font, and `mimeapps.list` picks which application opens each file type and URL scheme.
> [!NOTE]
> Linux `desktop` and `laptop` roles only. `.chezmoiignore.tmpl` skips `~/.config/fontconfig/**` and `~/.config/mimeapps.list` on other roles.
## Fontconfig
| Source (repo) | Target |
| --- | --- |
| `dot_config/fontconfig/fonts.conf` | `~/.config/fontconfig/fonts.conf` |
**~/.config/fontconfig/fonts.conf**
```xml
<fontconfig>
<match target="pattern">
<test name="family" qual="any">
<string>monospace</string>
</test>
<edit name="family" mode="prepend_first" binding="strong">
<string>VictorMono Nerd Font</string>
</edit>
</match>
</fontconfig>
```
Any font request that includes the generic `monospace` family gets `VictorMono Nerd Font` added to the front of its family list (`prepend_first`) with strong binding. Apps that ask for "monospace" therefore render in Victor Mono with Nerd Font glyphs, and fall back through fontconfig's normal monospace list if a glyph is missing. The file does not configure sans/serif families, hinting, antialiasing, or subpixel rendering. Those stay at system defaults.
Some tools set their own fonts. The terminals set fonts in their own configs (see [kitty](../terminal/kitty.md)).
### Font packages
Victor Mono Nerd Font is installed on every role (including `server`) by `run_onchange_before_10-packages.sh.tmpl` from `.chezmoidata/packages.yaml`, not only on desktop roles:
Package: `ttf-victor-mono-nerd`, from pacman (`packages.arch.pacman`).
`fonts.conf` is desktop/laptop only; the font package is also installed on `server`.
## Default applications
| Source (repo) | Target |
| --- | --- |
| `dot_config/mimeapps.list` | `~/.config/mimeapps.list` |
`mimeapps.list` is the XDG file that `xdg-open`, GTK/Qt file dialogs, and browsers use to choose a handler. `[Default Applications]` sets the preferred handler. `[Added Associations]` adds entries to "Open with" lists.
### Default applications
| Group | MIME types / schemes | Handler (`.desktop`) |
| --- | --- | --- |
| Text and scripts | `text/plain`, `text/x-shellscript`, `text/x-python`, `text/x-script.python` | `vim.desktop` |
| Notes | `text/markdown`, `application/x-obsidian-canvas`, `application/x-obsidian-base`, `x-scheme-handler/obsidian` | `obsidian.desktop` (`obsidian` from `packages.arch.desktop.pacman`) |
| Web pages | `text/html`, `application/xhtml+xml`, `application/x-extension-htm`, `-html`, `-shtml`, `-xhtml`, `-xht` | `brave-origin.desktop` |
| Web links | `x-scheme-handler/http`, `https`, `chrome` | `brave-origin.desktop` |
| Browser internals | `x-scheme-handler/about`, `unknown` | `chromium.desktop` |
| PDF | `application/pdf` | `brave-origin.desktop` |
| Directories | `inode/directory` | `io.github.lgse.Strata.desktop` ([strata](../chezmoi/scripts.md#15-tools), which also registers the `org.freedesktop.FileManager1` service for "Open file location" and serves the portal file chooser) |
| Mail | `x-scheme-handler/mailto`, `fastmail` | `com.fastmail.Fastmail.desktop` (`fastmail` from `packages.arch.desktop.aur`) |
| Windows executables | `application/vnd.microsoft.portable-executable` | `wine.desktop` |
| AI tools | `x-scheme-handler/claude` | `com.anthropic.Claude.desktop` |
| | `x-scheme-handler/claude-cli` | `claude-code-url-handler.desktop` |
| | `x-scheme-handler/opencode` | `ai.opencode.desktop.desktop` |
| | `x-scheme-handler/antigravity` | `antigravity.desktop` |
| | `x-scheme-handler/piebald` | `piebald-handler.desktop` |
| | `x-scheme-handler/openhuman` | `OpenHuman-handler.desktop` |
| Productivity | `x-scheme-handler/todoist`, `com.todoist` | `todoist.desktop` |
| | `x-scheme-handler/notion` | `notion.desktop` |
| | `x-scheme-handler/anytype` | `anytype.desktop` |
| | `x-scheme-handler/tolaria` | `tolaria-handler.desktop` |
| | `x-scheme-handler/tldraw-offline` | `tldraw-offline.desktop` |
| | `x-scheme-handler/figma` | `figma-linux.desktop` |
| Chat | `x-scheme-handler/slack` | `slack.desktop` |
| | `x-scheme-handler/discord-647066573147996160` | `discord-647066573147996161.desktop` |
| Feeds | `x-scheme-handler/follow`, `folo` | `folo.desktop` |
### Added associations
| MIME types / schemes | Also offered |
| --- | --- |
| `http`, `https`, `chrome` schemes; `text/html`, `application/xhtml+xml`, and the `x-extension-*` web types | `brave-origin.desktop`, `userapp-Floorp-8MTFP3.desktop` |
| `x-scheme-handler/mailto` | `userapp-Evolution-PCEYQ4.desktop` |
| `application/vnd.microsoft.portable-executable` | `wine.desktop` |
| `application/pdf` | `brave-origin.desktop` |
| `x-scheme-handler/opencode` | `ai.opencode.desktop.desktop` |
The added mail association is Evolution, but the default mail handler is the Fastmail app.
> [!TIP]
> In symlink mode, `~/.config/mimeapps.list` is a symlink into the repo. When `xdg-mime default` or a "set as default" dialog updates it, the tool either writes through the symlink and edits the repo file directly, or replaces the symlink with a regular file. Check `git status` or `chezmoi status` after changing defaults.
## Related
- [Umbriel](umbriel.md): the compositor these defaults serve.
- [Installation](../installation.md): role selection that decides whether this layer applies.
+184
View File
@@ -0,0 +1,184 @@
# Umbriel
Umbriel scrolling compositor config — Noctalia-only session, layout and springs, named scratchpads, outputs, and keybindings.
[Umbriel](https://docs.noctalia.dev/umbriel/) is a wlroots scrolling compositor from the Noctalia project. The config sets up the layout, window rules, springs, binds, and per-app scratchpads. The session starts only `noctalia`, which provides the launcher, clipboard history, polkit agent, notifications, and OSD.
Noctalia's polkit agent is off by default. `~/.config/noctalia/config.toml` (the [prdlk/noctalia](https://github.com/prdlk/noctalia) external, see [externals](../chezmoi/externals-and-ignore.md#chezmoiexternals); merged under the GUI's unmanaged `~/.local/state/noctalia/settings.toml`) sets `[shell] polkit_agent = true`, so `pkexec` and other privileged actions prompt in a Noctalia panel. `polkitd` itself is D-Bus activated (`polkit.service` is static; nothing to enable).
> [!NOTE]
> `desktop` and `laptop` roles only (`.chezmoiignore.tmpl`). `umbriel-git` comes from the AUR (`packages.arch.desktop.aur`) and pulls in its portal backend `xdg-desktop-portal-umbriel-git` (screenshots and screen sharing for portal clients). The `[cachyos]` `umbriel` build (`0.1.0.r1213`) lacks `window-move-by`, which `binds.toml` uses, and rejects the config. `umbriel-git` conflicts with it, so on a machine that already has the repo build, swap them by hand once (`yay -S umbriel-git`, accepting the removal); the package script runs `--noconfirm`, which declines that removal.
## Files
| Source (repo) | Target |
| --- | --- |
| `dot_config/umbriel/config.toml` | `~/.config/umbriel/config.toml`: includes, session, environment, input, layout, appearance, animation |
| `dot_config/umbriel/outputs.toml` | `~/.config/umbriel/outputs.toml` |
| `dot_config/umbriel/rules.toml` | `~/.config/umbriel/rules.toml`: scratchpads, window and layer rules |
| `dot_config/umbriel/binds.toml` | `~/.config/umbriel/binds.toml` |
| `dot_local/bin/executable_umbriel-launch` | `~/.local/bin/umbriel-launch` |
| `dot_local/bin/executable_umbriel-smart-move` | `~/.local/bin/umbriel-smart-move` |
| `dot_local/bin/executable_umbriel-float-square` | `~/.local/bin/umbriel-float-square` |
Umbriel watches these files and applies a valid save immediately; `umbriel config validate` checks them without a session. Include paths resolve against the symlinks in `~/.config/umbriel`, not the chezmoi source. Defining `[keybinds]` replaces Umbriel's built-in binds, so `binds.toml` is the complete set.
### Theme
`~/.config/umbriel/noctalia.toml` holds the colors. Noctalia's umbriel template writes it on every theme change and its post-hook keeps `"noctalia.toml"` last in `[include.optional]`; the file is not managed by chezmoi.
## Settings
| Area | Value |
| --- | --- |
| Keyboard | `us`, repeat delay 400 ms, rate 50, NumLock on |
| Touchpad | natural scroll, tap, left-right-middle, sensitivity 1.0 |
| Tablet, touch | mapped to `eDP-1` |
| Cursor | `Bibata_Ghost` (dark translucent Bibata, AUR `bibata-cursor-translucent`) 28, hidden while typing, follows keyboard focus (so scratchpads open on the output focus moved to). Umbriel exports it as `XCURSOR_THEME` and over XSETTINGS; GTK apps on Wayland read the GNOME settings instead, set once with `gsettings set org.gnome.desktop.interface cursor-theme Bibata_Ghost` and `… cursor-size 28` (dconf, not managed) |
| Layout | gap 8, presets 0.333 / 0.5 / 0.667, new columns 1/3 (0.8 on the laptop panel, see [Outputs](#outputs)), focus never centers, a lone column centers |
| Appearance | corner radius 10, no shadows, wallpaper-only blur on every window (radius 10, 4 passes, strong enough to hide wallpaper detail behind Brave Origin's own translucent background), tab bar hidden for one tab |
| Activation | apps may focus and reveal their windows (`focus_on_activate`), e.g. Noctalia notification actions |
| Overview | zoom 0.4; no hot corner |
| Animation | springs `0.82,1125` (open), `0.88,2025` (close), `0.85,1463` (move, overview, scratchpad), `0.78,1350` (workspaces) |
| Environment | `TERMINAL=ghostty` (default terminal), `ELECTRON_OZONE_PLATFORM_HINT=auto`, `QT_QPA_PLATFORM=wayland`, `QT_QPA_PLATFORMTHEME=kde`, `QT_STYLE_OVERRIDE=Darkly` |
Umbriel owns `XDG_CURRENT_DESKTOP`, so the config does not override it.
## Outputs
Matched by monitor identity (`umbriel outputs` → `Config name`). The external scales bring each display to about 110 logical pixels per inch (the ultrawide's native density), so windows keep their size across them. The laptop panel runs at 2 (112 logical ppi, 1280x800). It sits at the origin and every external sits directly to its left at negative x, bottoms aligned. The externals are used one at a time and share that slot.
| Display | Physical | Scale | Logical | Position | Other |
| --- | --- | --- | --- | --- | --- |
| Laptop (Tianma TL134ADXP03, `eDP-1`) | 2560x1600, 224 ppi | 2 | 1280x800 | `0, 0` | VRR in fullscreen, cursor starts here, new scrolling columns 0.8 wide |
| Apple Studio Display | 5120x2880, 218 ppi | 2 | 2560x1440 | `-2560, -640` | |
| Samsung S34CG50 ultrawide | 3440x1440@100, 110 ppi | 1 | 3440x1440 | `-3440, -640` | VRR in fullscreen, workspaces 1–9 start in dwindle |
| Portable HDMI (AOP 16PM1QB) | 1920x1080, 141 ppi, rotated 90° | 1.25 | 864x1536 | `-864, -736` | |
| Portable USB-C (ASUS MB16AC) | 1920x1080, 141 ppi | 1.25 | 1536x864 | `-1536, -64` | |
Umbriel sets the layout mode per workspace, not per output, so the ultrawide's dwindle default is nine `[[workspace]]` rules in `outputs.toml`, one for each index 1–9 on that monitor. A workspace past 9 starts in scrolling. `Mod+W` still toggles any workspace between scrolling and dwindle.
The Studio Display's phantom 640x480 connector needs no rule: Umbriel leaves connectors without a preferred mode or identity disabled.
## Scratchpads
Named scratchpads hold one app each. A window rule sends each app into its scratchpad when it opens; toggling an empty scratchpad runs `spawn_when_empty`. A shown scratchpad window floats centered on the output under the pointer at 48% × 77% of its usable area (`default_floating_size`, the last window rule in `rules.toml`: 1638×1109 on the ultrawide, 614×594 on the laptop panel, 1229×1109 on the Studio Display) over a desktop dimmed to 0.6. `animation.scratchpad.maximize` is off. The size is a default: a resident that was already open before the rule changed keeps its old geometry until it is reopened.
| Scratchpad | App id | Launch | Keys |
| --- | --- | --- | --- |
| `tern` | `so.stencil.tern` | `tern` | `Super+A`, `Super+Alt+Ctrl+H` |
| `claude` | `com.anthropic.Claude` | `claude-desktop` | `Super+Alt+Ctrl+L`, `Super+Ctrl+A` |
| `fastmail` | `com.fastmail.Fastmail` / `com-fastmail-fastmail` | `gtk-launch com.fastmail.Fastmail` | `Super+Alt+Ctrl+E` |
| `beeper` | `Beeper` | `gtk-launch beeper` | `Super+Alt+Ctrl+M`, `Super+Alt+Ctrl+B` |
| `home` | `brave-home.google.com__*` | `gtk-launch 'Google Home'` | `Super+Ctrl+H` |
| `lmstudio` | `ai.elementlabs.lmstudio` | `gtk-launch ai.elementlabs.lmstudio` | `Super+Ctrl+L` |
## Window rules
| Match | Rule |
| --- | --- |
| every window | blur |
| `Folo`, `Spotify`, `zen`, `brave-origin`, `gemini-desktop`, `claude-desktop`, `kitty*`, `zed`, `obsidian`, `Beeper`, `chromium`, `com.mitchellh.ghostty` | opacity 0.9, tiled, focused |
| `brave-origin`, `zen`, `chromium` | opacity 0.97 (overrides the 0.9 above) |
| `dev.noctalia.Noctalia` | floating 1080 × 920 |
| `dev.noctalia.UmbrielSharePicker` | floating 800 × 600 |
| `io.github.lgse.Strata`, `org.gnome.Nautilus`, `com.gabm.satty` | floating, half the output wide, focused |
| `brave-youtube.com__*` | floating, pinned, 30% × 30%, 10 px from the bottom-left |
| title `Picture-in-Picture` / `Picture in picture` | floating, unfocused, opaque, 24 px from the top-right of `eDP-1` |
| YouTube and chat/mail/dashboard apps (`chromium`, Calendar, Discord, Slack, Gemini, Hermes, Todoist, Cloudflare web apps) | laptop panel, workspace 1, maximized |
| `zed`, `obsidian`, sticky notes, `vacuumtube`, `Fladder`, `kitty`, `kitty-herdr`, `kitty-tmux` | Apple Studio Display |
| the six scratchpad apps | their scratchpad, floating 48% × 77% centered |
Noctalia's bar, panels, notifications, dock, OSD, and desktop widgets get blur through a layer rule.
## Keybindings
`Mod` is Super.
### Shell and session
| Keys | Action |
| --- | --- |
| `Mod+Space` | Noctalia launcher |
| `Mod+Shift+Space` | Noctalia launcher, emoji search (`/emo`) |
| `Super+Ctrl+Shift+BackSpace` | Noctalia launcher, session actions (`/session`: lock, suspend, reboot, shutdown, logout) |
| `Mod+P` | Noctalia clipboard history |
| `Mod+Period` / `Mod+Comma` | Noctalia control center / settings |
| `Super+Alt+Ctrl+N` | Noctalia notes panel |
| `Mod+Shift+B` | Noctalia bookmarks panel (`dunarand/bookmarks` plugin) |
| `Mod+Ctrl+R` | ostt recorder plugin |
| `Mod+Tab` | overview |
| `Mod+Shift+Q` | Noctalia session menu |
| `Mod+Shift+E` | quit Umbriel (asks first) |
| `Mod+Escape` | pass shortcuts through to the focused app (works while inhibited) |
| `Mod+S`, `Print` | region screenshot |
| `Mod+Ctrl+S`, `Ctrl+Print` | focused-monitor screenshot |
| `Mod+Ctrl+Shift+S` | all-monitors screenshot |
| `Mod+F24` | voxtype dictation (`--profile hermes`) |
| media, volume, brightness keys | `noctalia msg …`, also on the lock screen |
### Apps
`umbriel-launch PATTERN COMMAND…` focuses the next window whose app id matches `PATTERN` (case-insensitive), cycling on repeated presses, and runs `COMMAND` through `umbriel msg spawn` when none is open. It skips scratchpad windows. The binds call it as `~/.local/bin/umbriel-launch` because the session `PATH` has no `~/.local/bin`.
| Keys | Cycles | Launches |
| --- | --- | --- |
| `Super+Alt+Ctrl+J` | Ghostty, kitty, alacritty | `ghostty` |
| `Super+Alt+Ctrl+K` | browsers: Brave Origin, Chromium, Firefox (not web apps) | `brave-origin` |
| `Super+Alt+Ctrl+G` | Ghostty | `ghostty` |
| `Super+Alt+Ctrl+O` | Obsidian | `obsidian` |
| `Super+Alt+Ctrl+F` | strata | `gtk-launch io.github.lgse.Strata` |
| `Super+Alt+Ctrl+W` | tldraw offline | `gtk-launch tldraw-offline` |
| `Super+Alt+Ctrl+T` | Todoist | `gtk-launch todoist` |
| `Super+Alt+Ctrl+Y` | web apps (`webapp-*`, `chrome-*`, `brave-*__*`) | `gtk-launch YouTube` |
| `Super+Alt+Ctrl+Space` | Sticky Notes Canvas | `gtk-launch io.github.faridjaff.StickyNotesCanvas` |
| `Super+Ctrl+G` | Gemini | `gemini-desktop` |
| `Mod+Shift+G` | — | Goliath kitty (`--class=kitty-goliath`) |
### Windows and layout
| Keys | Action |
| --- | --- |
| `Mod+H` / `Mod+L` | focus left / right, or the output on that side at the strip's edge |
| `Mod+J` / `Mod+K` | focus down / up, or the next / previous workspace at the edge |
| `Mod+BackSpace` | previously focused window |
| `Mod+WheelUp` / `Mod+WheelDown` | focus left / right |
| `Mod+Left` / `Mod+Right` / `Mod+Up` | focus the output in that direction |
| `Mod+O`, `Super+Ctrl+J` / `Super+Ctrl+K` | next / previous output |
| `Mod+Shift+H` / `Mod+Shift+L` | [smart move](#smart-move) left / right: consume or expel, then on to the next output |
| `Super+Ctrl+Shift+H` / `Super+Ctrl+Shift+L` | move column first / last |
| `Mod+Shift+J` / `Mod+Shift+K` | move column to next / previous workspace |
| `Mod+Shift+Down` / `Mod+Shift+Up` | move column to the right / left output |
| `Mod+Shift+O`, `Mod+Ctrl+Shift+J` / `Mod+Ctrl+Shift+K` | move window to next / previous output |
| `Mod+R` / `Mod+Shift+R` | cycle width / height presets |
| `Alt+Shift+H` / `Alt+Shift+L` | width −10% / +10% |
| `Alt+Shift+J` / `Alt+Shift+K` | height −10% / +10% |
| `Alt+H` / `Alt+J` / `Alt+K` / `Alt+L` | move the focused floating window 50 px left / down / up / right (`window-move-by`, held keys repeat; kept inside the usable area) |
| `Mod+F` | full-width column |
| `Mod+Shift+F` | maximize to the output edges |
| `Mod+Ctrl+F` | fullscreen |
| `Mod+C` | floating window: [square it](#float-square) at the usable height minus 4 px top and bottom, centered; tiled: center column |
| `Mod+T` | toggle floating |
| `Mod+W` | toggle the workspace between the scrolling and dwindle layouts |
| `Mod+G` | tab the focused window with the windows stacked in its column, or stack a tab group again (scrolling layout; dwindle has no columns). Windows join a group by dragging onto its tab bar |
| `Mod+Q` | close window |
| `Mod+1`…`Mod+9`, `Alt+Q W E R Y U I O` | workspace 1–9 / 1–8 |
| `Mod+Shift+1`…`9`, `Alt+Shift+Q`…`O` | move window to that workspace |
Workspaces are dynamic per output.
### Smart move
`umbriel-smart-move left|right` consumes or expels the window left or right and continues across outputs. In the scrolling layout it picks one action for the focused window:
| Focused window | Action |
| --- | --- |
| stacked with other windows in its column | expel it to a new column on that side |
| alone, with a column on that side | consume it into that column |
| alone, at the strip's end | move it to the output on that side (nothing at the outermost output) |
Two presses step a window past its neighbour: the first stacks it into the neighbour's column, the second expels it on the far side. On dwindle and master workspaces it runs `window-move-or-output-left/right`. Floating and scratchpad windows stay put.
### Float square
`umbriel-float-square` (`Mod+C`) acts on the window with keyboard focus (`.active` in `umbriel windows --json`). A floating window becomes a square whose side is the output's usable height (below Noctalia's bar) minus 4 px above and below (`PAD`): `window-set-secondary-extent` and `window-set-primary-extent` get that side as a fraction of the usable height and width. The script then waits up to 1 s for the client to commit the new width, because `window-center` centers the committed size, and centers it. On the laptop panel that is 764×764 at y 32; on the ultrawide 1404×1404. A tiled window gets `column-center`, the previous `Mod+C`.