feat(terminal): Kitty only — drop Ghostty (#95)
Some checks failed
Check / eval (push) Has been cancelled

Ghostty's OpenGL 4.3 floor broke the Acer (HD 4000 / 4.2). Dual-terminal
support (default Ghostty + install-time Kitty fallback) was more complexity
than it was worth.

- Remove ghostty.nix / nomarchy.ghostty.enable
- Kitty always installed and themed from theme-state
- Default nomarchy.terminal = kitty; SUPER+Return, doctor, calendar,
  what-changed use kitty --class=com.nomarchy.*
- Drop install-time glxinfo probe and mesa-demos on the installer
- Docs/REQUIREMENTS no longer list OpenGL 4.3 as a terminal floor

Verified: V0 flake check; option-docs; installer-safety; template HM has
kitty, no ghostty; menu/calendar emit classed kitty launches.
This commit is contained in:
2026-07-15 09:51:27 +01:00
parent 1e648b6c49
commit 545e40f4d9
32 changed files with 151 additions and 299 deletions

View File

@@ -19,7 +19,7 @@ partial.
┌──────────────────────────────────────────────────────────────────────────┐
│ Home Manager bakes EVERYTHING into one read-only generation: │
│ Hyprland (colors/gaps/borders) Waybar (palette or whole-swap) │
Ghostty (full ANSI palette) btop (asset or generated) │
Kitty (full ANSI palette) btop (asset or generated) │
│ Stylix → GTK, Qt, cursors, fonts │
└───────────────────────────────────┬──────────────────────────────────────┘
@@ -56,7 +56,7 @@ Flat on purpose. Two module trees, one options file each, no hidden layers.
│ ├── stylix.nix # GTK/Qt/cursors/fonts from the same JSON
│ ├── hyprland.nix # all JSON-driven
│ ├── waybar.nix
│ ├── ghostty.nix
│ ├── kitty.nix
│ ├── btop.nix
│ ├── rofi.nix # launcher + nomarchy-menu (calc, emoji, clip…)
│ ├── keybinds.nix # single source: Hyprland binds + SUPER+? sheet
@@ -103,8 +103,8 @@ probably shouldn't exist.
## 2. Try it first (live ISO)
**Before you install:** check **[docs/REQUIREMENTS.md](docs/REQUIREMENTS.md)**
(UEFI x86_64, **OpenGL 4.3** for the default terminal, disk planning for the
Nix store + BTRFS snapshots — 128GiB is the comfortable floor).
(UEFI x86_64, disk planning for the Nix store + BTRFS snapshots — 128GiB is
the comfortable floor).
Boot the full desktop from a USB stick or VM without installing anything:
@@ -244,8 +244,8 @@ two tables below are split along exactly that line.
| Option | Default | Purpose |
|---|---|---|
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json |
| `nomarchy.terminal` | `"ghostty"` (or `"kitty"`) | Terminal for keybinds and `$TERMINAL`; installer sets `settings.terminal = "kitty"` when OpenGL < 4.3 |
| `nomarchy.kitty.enable` | `false` | Themed Kitty (also auto-on when terminal is kitty) |
| `nomarchy.terminal` | `"kitty"` | Terminal for keybinds and `$TERMINAL` (Kitty is the only shipped/themed emulator) |
| `nomarchy.kitty.enable` | `true` | Nomarchy's Kitty config (palette/font/opacity from theme-state) |
| `nomarchy.keyboard.layout` | `"us"` | XKB layout for the Hyprland session (installer writes the matching `services.xserver.xkb` in system.nix; the console + LUKS prompt follow via the distro default) |
| `nomarchy.keyboard.variant` | `""` | XKB variant for the session |
| `nomarchy.keyboard.devices` | `{}` | Per-device layout overrides (Hyprland `device` blocks keyed by `hyprctl devices` name) — e.g. an external keyboard with its own layout/variant |
@@ -264,7 +264,6 @@ two tables below are split along exactly that line.
| `nomarchy.yazi.enable` | `true` | yazi TUI file manager, themed + curated plugins |
| `nomarchy.osd.enable` | `true` | swayosd on-screen display for volume/brightness/mute |
| `nomarchy.shell.enable` | `true` | zsh + starship prompt + bat/eza/zoxide (zsh is the default login shell) |
| `nomarchy.ghostty.enable` | `true` | Nomarchy's Ghostty |
| `nomarchy.btop.enable` | `true` | btop with per-theme colors |
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo |
@@ -376,7 +375,7 @@ source. It must be git-tracked (`nomarchy-theme-sync` runs
`nomarchy-theme-sync apply <theme>` merges the preset into the JSON and runs
`home-manager switch` (override the command with `$NOMARCHY_REBUILD`, or pass
`--no-switch` to only write). Everything is baked: Hyprland, Waybar, Ghostty,
`--no-switch` to only write). Everything is baked: Hyprland, Waybar, Kitty,
btop, and — via Stylix, mapped onto base16 roles — GTK, Qt, cursors and
fonts. No runtime patching means no partial states, and `home-manager
generations` is also your theme history. Waybar even restyles in place: it

View File

@@ -27,9 +27,9 @@ in [`docs/ROADMAP.md`](../docs/ROADMAP.md); map in
### Live ISO / install hardware findings — Acer Aspire M5-481T + Dell XPS 9350
Bernardo, real installs 2026-07-1314 (photos of the install end screens and
post-boot sessions). Preserve separation: the installer bake failure, the
flake pin, and the Ghostty GL floor are different root causes even when they
show up on the same machine.
post-boot sessions). Preserve separation: the installer bake failure and the
flake pin are different root causes even when they show up on the same machine.
(Terminal / Ghostty-on-Acer → shipped as Kitty-only, #95.)
### 123. Installer HM pre-activate aborts on dconf / missing XDG_RUNTIME_DIR
@@ -144,26 +144,6 @@ template source. Pass = Chromium launches after installation and HTTP/HTTPS
mime defaults resolve to `chromium-browser.desktop` (and the intended live-ISO
browser posture is explicit).
### 95. Live ISO/install: Ghostty does not open on Acer (old GL) — **install fallback shipped**
**Machine:** Acer Aspire M5-481T only (Intel HD 4000, OpenGL **4.2**). XPS
starts Ghostty fine. Generation ceiling documented in `docs/REQUIREMENTS.md`.
**Shipped (this iteration):** installer probes `glxinfo`; if OpenGL &lt; 4.3,
writes `settings.terminal = "kitty"` into theme-state. `modules/home/kitty.nix`
installs and **themes** Kitty from the same palette/font/opacity as Ghostty.
Default HM keeps Ghostty only (no kitty package). Manual override:
`settings.terminal = "kitty"` or `nomarchy.terminal = "kitty"`.
**Still open:**
- **V3** on the Acer: fresh install (or hand-set terminal + `nomarchy-home`)
→ SUPER+Return opens themed Kitty; Ghostty may still fail if launched by
name (expected).
- Doctor / calendar classed windows still hardcode `ghostty` — may fail on
the same GL floor (separate small follow-up if they matter on old HW).
- Live ISO session on HD 4000 still defaults to Ghostty until install (or a
live-side probe).
### 98. Boreal: button text renders black and is difficult to read
Audit GTK button foreground/background contrast under Boreal, including the
@@ -222,7 +202,7 @@ a staircase.
a real Nomarchy machine.** Chase the *fallback*, not one font's charset; this
was got wrong twice while filing, both times by checking a single font:
- The mono face is **per theme** (`ghostty.nix:22``t.fonts.mono` from the
- The mono face is **per theme** (`kitty.nix``t.fonts.mono` from the
theme JSON), not stylix's default. **Boreal — the default theme and the base
state — is `GeistMono Nerd Font`**; the other 23 themes are `JetBrainsMono
Nerd Font`. Any answer must hold for both.

View File

@@ -22,7 +22,7 @@ confidence, default identity, release bar) live in
ergonomic writer for the flake. Where a toggle can take effect without a
rebuild, it must (`--no-switch` + flip the running service).
4. **Beautiful.** One JSON themes the entire desktop coherently — Hyprland,
Waybar, Ghostty, btop, rofi, GTK/Qt, boot splash, greeter. Every new
Waybar, Kitty, btop, rofi, GTK/Qt, boot splash, greeter. Every new
surface follows the palette. Informative, self-gating Waybar modules
(they hide when irrelevant). No unthemed corner survives contact with
the theme switcher.

View File

@@ -436,12 +436,9 @@ the **T14s** (webcam case).
**without** running `home-manager switch` by hand. **Fail** = still
need the recovery one-liner, or GTK/nm-applet still wrong until a
manual switch (then the bake is still incomplete).
- [ ] **#95 themed Kitty fallback on Acer M5-481T** — after install from an
ISO that probes GL &lt; 4.3 (or set `settings.terminal = "kitty"` +
`nomarchy-home`): SUPER+Return opens **Kitty** with Boreal (or current
theme) colors/font — not unthemed stock. `theme-state.json` should
show `"terminal": "kitty"`. Ghostty may still refuse if launched by
name (expected on HD 4000). XPS / modern-GL machines keep Ghostty.
- [ ] **#95 Kitty-only terminal on Acer M5-481T** — after rebuild/install
from main: SUPER+Return opens **themed Kitty**; System Doctor opens
a floating classed Kitty window. No Ghostty on PATH required.
- [ ] **#124 flake pin after main-ISO install** — on a machine installed
from a **main-built** ISO (post-fix): `~/.nomarchy/flake.nix`
nomarchy input must not re-resolve to a lagging `v1` that lacks

View File

@@ -19,7 +19,19 @@ Template:
---
## 2026-07-15 — #95: themed Kitty when OpenGL < 4.3 (this commit)
## 2026-07-15 — #95 complete: Kitty is the only terminal (this commit)
- **Task:** Bernardo: make kitty default and only option — drop dual-terminal
complexity (Ghostty failed on Acer OpenGL 4.2; fallback was more code).
- **Did:** Removed `ghostty.nix` and `nomarchy.ghostty.enable`. Kitty always
installed + themed; default `nomarchy.terminal = "kitty"`. Doctor, calendar,
what-changed → `kitty --class=com.nomarchy.*`. Dropped install-time GL
probe + mesa-demos. Updated README/REQUIREMENTS/OVERRIDES/TESTING/tools.
- **Verified:** V0 flake check; downstream-template-home builds with kitty,
no ghostty; installer-safety green.
- **Pending:** V3 Acer SUPER+Return + doctor float (HARDWARE-QUEUE).
- **Next suggestion:** #123 (HM pre-activate dconf).
## 2026-07-15 — #95: themed Kitty when OpenGL < 4.3 (superseded above)
- **Task:** Bernardo: when GL &lt; 4.3 automatically add kitty — and theme it.
- **Did:** `modules/home/kitty.nix` themes Kitty from theme-state (same
palette/font/opacity as Ghostty); enables when `nomarchy.terminal` is

View File

@@ -10,14 +10,12 @@ iteration would otherwise rediscover.
- **Doctor float V2:** `THEME=<slug> nix build --impure -f tools/doctor-float.nix`
— softGL Hyprland, `nomarchy-menu doctor`, asserts
`class=com.nomarchy.doctor` + `floating` + centered midpoints +
screenshots. Ghostty *does* start here under softGL (classed one-shot);
size often stays Ghosttys default 800×600 (client geometry wins over
the percent `size` windowrule).
- **theme-shot softGL cannot start Ghostty** — `btop.png` is best-effort
screenshots (Kitty `--class=…`). SoftGL may still struggle with a GPU
terminal; size can ignore percent windowrules if client geometry wins.
- **theme-shot softGL may not start Kitty** — `btop.png` is best-effort
(usually identical to desktop). Guest asserts on
`~/.config/btop/themes/nomarchy.theme` prove baking; the TUI look is
hardware/GL tier (HARDWARE-QUEUE). Doctor float is the counter-example
that a *classed* one-shot Ghostty can still map under softGL.
hardware/GL tier (HARDWARE-QUEUE).
- **Waybar `custom/doctor` tripwire:** status helper must invoke
`nomarchy-doctor` by **absolute store path** (waybar's env can miss
system PATH → `command -v … || exit 0` self-hides forever); empty
@@ -85,9 +83,9 @@ iteration would otherwise rediscover.
(`LIBGL_ALWAYS_SOFTWARE` on virtio-gpu) + `machine.screenshot()` QMP
dump — prototyped 2026-06-19, kept as the fallback for theme previews
(§ Visual theme picker).
- Hyprland/Ghostty need guest GL (`virtio-vga-gl`, `gl=on`) in
interactive QEMU or the session won't start; black screen ≈ missing GL
(docs/TESTING.md § gotchas).
- Hyprland needs guest GL (`virtio-vga-gl`, `gl=on`) in interactive QEMU
or the session won't start; black screen ≈ missing GL
(docs/TESTING.md § gotchas). Kitty is the sole terminal (no Ghostty).
- No KVM = slow, not broken; don't read slowness as failure.
## Known-broken / watchlist

View File

@@ -20,7 +20,7 @@ consumes the palette from the state JSON, never a side file.
## Design responsibilities
1. **Holistic design:** a theme spans Hyprland (borders, shadows,
animations), Waybar, Ghostty, btop, fastfetch, rofi, and wallpaper —
animations), Waybar, Kitty, btop, fastfetch, rofi, and wallpaper —
one coherent identity, no unthemed corner.
2. **Color theory:** create or adapt advanced palettes. Draw inspiration
from established aesthetics (Everforest, Nord, Gruvbox) or r/unixporn

View File

@@ -11,7 +11,7 @@ rule of thumb:
Everything that defines the *look* flows from `theme-state.json`, the single
source of truth. Change it with `nomarchy-theme-sync`, which writes the JSON
and rebuilds — one generation, applied to Hyprland, Waybar, Ghostty, btop and
and rebuilds — one generation, applied to Hyprland, Waybar, Kitty, btop and
Stylix at once:
```sh
@@ -98,9 +98,8 @@ in your `home.nix` wins — no `mkForce` needed:
animations.enabled = false;
};
programs.ghostty.settings = {
window-padding-x = 4; # was 12
window-decoration = true;
programs.kitty.settings = {
window_padding_width = 4; # was 12
};
}
```

View File

@@ -2,7 +2,7 @@
What Nomarchy expects of a machine. This is a **living floor**, not a
marketing sheet — numbers come from measured installs and known software
floors (Ghostty, NixOS, the ISO). When a real machine pushes a bound, update
floors (NixOS, the ISO, desktop GPU). When a real machine pushes a bound, update
this file in the same change.
Related: [HARDWARE.md](HARDWARE.md) (profiles/drivers),
@@ -22,39 +22,22 @@ Related: [HARDWARE.md](HARDWARE.md) (profiles/drivers),
## Graphics (default desktop)
The default terminal is **Ghostty**, which requires **OpenGL 4.3** (desktop
profile). That is a **GPU generation** limit, not a “driver not installed”
problem:
The sole terminal is **Kitty** (GPU-accelerated OpenGL, themed from
theme-state). It runs on older integrated GPUs that reject Ghosttys OpenGL
**4.3** floor — notably **Intel HD 4000 / Ivy Bridge** (Acer Aspire M5-481T
reported OpenGL **4.2** and could not start Ghostty). That is why Nomarchy
standardized on Kitty only: one terminal to theme, one set of classed windows
(doctor / calendar), no dual-stack or GL probe at install.
| Generation (examples) | Typical max OpenGL (Mesa) | Default Ghostty |
|-----------------------|---------------------------|-----------------|
| Ivy Bridge / HD 4000 (e.g. **Acer Aspire M5-481T**, ~2012) | **4.2** | **Does not start** (`OpenGLOutdated`) |
| Haswell and newer Intel iGPU, most AMD GCN+, discrete GPUs of the last decade | ≥ 4.3 | OK |
| Dell XPS 9350 (Skylake) | ≥ 4.3 | OK (verified 2026-07) |
**Why 4.2 and not 4.3 on HD 4000?** The silicon and Mesas feature set for
that generation top out at OpenGL 4.2. No package upgrade on the distro can
turn Ivy Bridge into a 4.3 device. Ghostty is choosing a modern GL baseline
on purpose.
**Install-time fallback (shipped):** when `nomarchy-install` can probe OpenGL
(via `glxinfo` on the live session) and the version is **&lt; 4.3**, it writes
`settings.terminal = "kitty"` into the machines `theme-state.json`. Kitty is
enabled and **themed from the same JSON** as Ghostty (palette, mono font,
opacity). SUPER+Return then launches Kitty. Ghostty stays installed (doctor /
calendar classed windows still call it — those helpers may still fail on old
GL until a later follow-up).
If the probe fails (no display / headless VM), Ghostty remains the default —
do not guess. Existing installs can set the same by hand:
```json
"settings": { "terminal": "kitty" }
```
then `nomarchy-home` (or `home-manager switch`).
| Generation (examples) | Notes |
|-----------------------|--------|
| Ivy Bridge / HD 4000 (~2012) | Supported with Kitty (verified path on Acer M5-481T) |
| Haswell+ Intel, modern AMD, discrete GPUs | Supported |
| SoftGL / virtio-gpu VMs | Hyprland needs GL for the session; Kitty is best-effort under softGL |
Other Wayland clients vary; Hyprland itself is usually fine on these GPUs.
A working GPU (or software GL for VMs) is still required for the desktop
session — only the *terminal* no longer demands OpenGL 4.3.
---
@@ -154,8 +137,8 @@ Recovery menu. This requirements page only states why the disk fills up.
| Machine | Role |
|---------|------|
| **Acer Aspire M5-481T** (~2012, Intel HD 4000, OpenGL 4.2) | Ghostty floor (#95); install bake / old-HW QA |
| **Dell XPS 9350** (Skylake) | Install bake (#123); Ghostty OK |
| **Acer Aspire M5-481T** (~2012, Intel HD 4000) | Old-HW QA; drove Kitty-only terminal (#95) |
| **Dell XPS 9350** (Skylake) | Install bake (#123) |
| AMD dev box / Latitude / T14s | Ongoing V3 (HARDWARE-QUEUE) |
When you install on something older or smaller than the table, file what
@@ -167,7 +150,7 @@ broke in `agent/BACKLOG.md` and tighten this page.
| Item | Topic |
|------|--------|
| BACKLOG **#95** | Ghostty fallback when OpenGL &lt; 4.3 |
| BACKLOG **#95** | Kitty as sole terminal (shipped) |
| BACKLOG **#120** | Lighter netinstall ISO (download size ≠ installed size) |
| BACKLOG **#123** | Installer HM pre-activate (first-boot polish) |
| BACKLOG **#124** | Flake pin vs main/v1 lag after install |

View File

@@ -404,12 +404,13 @@ Design/decision records and a running log of shipped work (items marked
decision rather than a drive-by. Proved to fail: dropping snapshot makes it
name the missing entry. **V3 pending** — that the apps *launch* needs real
hardware (HARDWARE-QUEUE, Acer M5-481T).
- ✓ **Kitty fallback when OpenGL &lt; 4.3 (#95 partial):** Ghostty needs GL 4.3;
Ivy Bridge HD 4000 tops at 4.2 (Acer M5-481T). Installer probes `glxinfo`
and writes `settings.terminal = "kitty"` when below the floor; `kitty.nix`
themes Kitty from the same theme-state as Ghostty (ANSI, mono font,
opacity). Default machines stay Ghostty-only in the HM closure. V3 on Acer
still needed; doctor/calendar still invoke Ghostty by class.
- ✓ **Kitty is the only terminal (#95 complete):** Ghosttys OpenGL 4.3 floor
broke SUPER+Return (and classed doctor/calendar windows) on Ivy Bridge
HD 4000 (Acer M5-481T). Maintaining two terminals was pure complexity.
**Kitty only:** always installed, themed from theme-state (ANSI/font/opacity),
default `$TERMINAL` / SUPER+Return, doctor + calendar + what-changed use
`kitty --class=com.nomarchy.*`. Ghostty module and install-time GL probe
removed. V3: Acer SUPER+Return + doctor float.
- ✓ **Mime defaults must name a present .desktop (#119):** same bug class as
#94, one key over. `text/plain` pointed at `code.desktop` (vscode), which
the live ISO never ships — GIO skips the missing entry and leaves no

View File

@@ -47,7 +47,7 @@ nix build .#nixosConfigurations.nomarchy-live.config.system.build.isoImage
The script prefers UEFI (OVMF) with a legacy-BIOS fallback, uses KVM when
`/dev/kvm` is readable, and boots with `virtio-vga-gl` + `gl=on`
**Hyprland and Ghostty need real OpenGL in the guest**; without it the
**Hyprland (and the desktop session) need real OpenGL in the guest**; without it the
session may not start.
### What the live environment gives you
@@ -67,7 +67,7 @@ Work through these in order; each one exercises a different layer.
|---|---|---|
| 1 | Boots to Hyprland with the default theme wallpaper visible (Boreal) | greetd autologin, awww, session start |
| 2 | Waybar shows at top, themed (blue accent on dark) | HM waybar module, palette baking |
| 3 | `SUPER+Return` opens Ghostty with the default theme colors (Boreal) | terminal default, ANSI palette |
| 3 | `SUPER+Return` opens Kitty with the default theme colors (Boreal) | terminal default, ANSI palette |
| 4 | `btop` in the terminal is themed | per-theme asset baking |
| 5 | `nomarchy-theme-sync list` prints 24 presets | package, baked themes dir |
| 6 | `nomarchy-theme-sync apply gruvbox` → state written, `home-manager switch` runs, desktop re-themes, wallpaper changes | the whole engine: state write, pure eval, HM rebuild, wallpaper hook |

View File

@@ -89,8 +89,9 @@ in
# ISO is the desktop, so re-enable what it strips. Above all
# fontconfig (upstream forces it off at mkOverride 500): without it
# no configured family resolves — Waybar icons render as tofu and
# Ghostty silently falls back to the wrong font (seen on the
# Latitude 5410). Normal priority (100) beats the override.
# Kitty silently falls back to the wrong font (seen on the
# Latitude 5410 with Ghostty; same fontconfig footgun). Normal priority
# (100) beats the override.
fonts.fontconfig.enable = true;
# No boot splash on the install medium: the installer ISO boots its

View File

@@ -10,8 +10,7 @@
./stylix.nix # GTK/Qt/cursor/fonts from the same JSON
./hyprland.nix
./waybar.nix
./ghostty.nix
./kitty.nix # themed fallback when Ghostty cannot run (OpenGL < 4.3)
./kitty.nix # sole terminal (themed); doctor/calendar/--class load-bearing
./btop.nix
./rofi.nix # launcher theming + the nomarchy-menu dispatcher
./swaync.nix # notification daemon, themed from the same JSON

View File

@@ -1,48 +0,0 @@
# Ghostty — Nomarchy's default terminal, themed from theme-state.json.
# Colors, fonts and the full 16-color ANSI palette are baked from the
# JSON at eval time.
{ config, lib, ... }:
let
t = config.nomarchy.theme;
c = t.colors;
in
{
# Ghostty is ALWAYS installed — it's Nomarchy's default terminal and is
# load-bearing (SUPER+E file manager, the calendar launcher's classed
# window, etc.), so the distro enforces it. `nomarchy.ghostty.enable` now
# gates only whether Nomarchy's theming/config is applied — a user can
# keep ghostty but drop our config, they just can't remove ghostty itself.
programs.ghostty = {
enable = true;
enableBashIntegration = true;
settings = lib.mkIf config.nomarchy.ghostty.enable {
# ── Typography (from theme-state.json) ────────────────────────
font-family = t.fonts.mono;
font-size = t.fonts.size;
# ── Colors (from theme-state.json) ────────────────────────────
background = c.base;
foreground = c.text;
cursor-color = c.accent;
selection-background = c.overlay;
selection-foreground = c.text;
split-divider-color = c.surface;
# "N=#rrggbb" entries; Ghostty accepts repeated `palette` keys,
# which the HM module renders from this list.
palette = lib.imap0 (i: color: "${toString i}=${color}") t.ansi;
# ── Chrome ────────────────────────────────────────────────────
# background-opacity is theme-driven (normal priority — use the
# CLI); the rest are mkDefault so a plain home.nix value wins.
background-opacity = t.ui.terminalOpacity;
window-padding-x = lib.mkDefault 12;
window-padding-y = lib.mkDefault 12;
window-decoration = lib.mkDefault false;
gtk-single-instance = lib.mkDefault true;
confirm-close-surface = lib.mkDefault false;
};
};
}

View File

@@ -1026,15 +1026,14 @@ in
"float 1, match:class (?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$"
"center 1, match:class (?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$"
# Calendar popup (item 42): the Waybar clock's on-click runs
# nomarchy-calendar → calcurse in a ghostty window tagged with a
# distinct --class, so it floats centered instead of tiling.
# Calendar popup (item 42): nomarchy-calendar → calcurse in a
# kitty window tagged with a distinct --class, so it floats centered.
"float 1, match:class ^(com\\.nomarchy\\.calendar)$"
"size 60% 65%, match:class ^(com\\.nomarchy\\.calendar)$"
"center 1, match:class ^(com\\.nomarchy\\.calendar)$"
# Doctor sheet (System Doctor / Waybar custom/doctor click):
# nomarchy-menu doctor → ghostty --class=com.nomarchy.doctor.
# nomarchy-menu doctor → kitty --class=com.nomarchy.doctor.
"float 1, match:class ^(com\\.nomarchy\\.doctor)$"
"size 55% 70%, match:class ^(com\\.nomarchy\\.doctor)$"
"center 1, match:class ^(com\\.nomarchy\\.doctor)$"

View File

@@ -1,26 +1,13 @@
# Kitty — fallback terminal when Ghostty cannot run (OpenGL < 4.3 on
# older GPUs, e.g. Intel HD 4000). Themed from the same theme-state.json
# as Ghostty so a machine that needs the fallback still looks like
# Nomarchy. Enabled when nomarchy.terminal is "kitty" (installer sets
# that after a GL probe) or when nomarchy.kitty.enable is forced on.
# Kitty — Nomarchy's only terminal, themed from theme-state.json.
# Colors, fonts and the full 16-color ANSI palette are baked from the
# JSON at eval time (same contract Ghostty used to have). Always
# installed: SUPER+Return, SUPER+E, doctor, calendar, and $TERMINAL
# all depend on it.
{ config, lib, ... }:
let
t = config.nomarchy.theme;
c = t.colors;
# Default terminal may be a bare name ("kitty") or a path; match the
# basename so settings.terminal = "kitty" and nomarchy.terminal =
# "${pkgs.kitty}/bin/kitty" both light this module.
terminalIsKitty =
let
term = config.nomarchy.terminal;
base = lib.last (lib.splitString "/" term);
in
base == "kitty" || lib.hasPrefix "kitty " term;
enabled = config.nomarchy.kitty.enable || terminalIsKitty;
# Kitty colorN = ANSI 015 from the theme palette.
colorSettings = lib.listToAttrs (
lib.imap0 (i: color: {
name = "color${toString i}";
@@ -29,35 +16,37 @@ let
);
in
{
config = lib.mkIf enabled {
programs.kitty = {
enable = true;
shellIntegration.enableBashIntegration = true;
shellIntegration.enableZshIntegration = true;
# Kitty is ALWAYS installed. `nomarchy.kitty.enable` gates only whether
# Nomarchy's theming/config is applied — a user can keep kitty but drop
# our config; they cannot remove kitty itself without breaking the
# desktop's load-bearing classed windows.
programs.kitty = {
enable = true;
shellIntegration.enableBashIntegration = true;
shellIntegration.enableZshIntegration = true;
font = {
name = t.fonts.mono;
size = t.fonts.size;
};
settings = {
background = c.base;
foreground = c.text;
cursor = c.accent;
cursor_text_color = c.base;
selection_background = c.overlay;
selection_foreground = c.text;
url_color = c.accent;
active_border_color = c.accent;
inactive_border_color = c.surface;
# Match Ghostty's padding / opacity so the two terminals feel
# like the same product when a machine falls back.
background_opacity = t.ui.terminalOpacity;
window_padding_width = lib.mkDefault 12;
confirm_os_window_close = lib.mkDefault 0;
enable_audio_bell = lib.mkDefault false;
wayland_titlebar_color = lib.mkDefault "background";
} // colorSettings;
font = lib.mkIf config.nomarchy.kitty.enable {
name = t.fonts.mono;
size = t.fonts.size;
};
settings = lib.mkIf config.nomarchy.kitty.enable ({
background = c.base;
foreground = c.text;
cursor = c.accent;
cursor_text_color = c.base;
selection_background = c.overlay;
selection_foreground = c.text;
url_color = c.accent;
active_border_color = c.accent;
inactive_border_color = c.surface;
background_opacity = t.ui.terminalOpacity;
window_padding_width = lib.mkDefault 12;
confirm_os_window_close = lib.mkDefault 0;
enable_audio_bell = lib.mkDefault false;
wayland_titlebar_color = lib.mkDefault "background";
# Fresh windows for doctor/calendar --class launches (not one shared instance).
single_instance = lib.mkDefault false;
} // colorSettings);
};
}

View File

@@ -100,17 +100,17 @@ in
# ── Preferences ────────────────────────────────────────────────
terminal = lib.mkOption {
type = lib.types.str;
default = config.nomarchy.settings.terminal or "ghostty";
default = config.nomarchy.settings.terminal or "kitty";
example = "kitty";
description = ''
Terminal emulator command, used by keybinds and `$TERMINAL`.
Default is Ghostty. On GPUs below OpenGL 4.3 the installer writes
`settings.terminal = "kitty"` so SUPER+Return still works (Ghostty
needs 4.3; see docs/REQUIREMENTS.md). Set explicitly to override.
Terminal emulator command for keybinds and `$TERMINAL`. Nomarchy
ships and themes **Kitty only** (sole supported terminal works
on older GPUs that Ghostty's OpenGL 4.3 floor rejected). Override
only if you install another emulator yourself.
'';
};
kitty.enable = lib.mkEnableOption "Kitty with Nomarchy theming (palette/font/opacity from theme-state); also auto-on when nomarchy.terminal is kitty (OpenGL < 4.3 install fallback)";
kitty.enable = lib.mkEnableOption "Nomarchy's Kitty configuration (palette/font/opacity from theme-state)" // { default = true; };
keyboard.layout = lib.mkOption {
type = lib.types.str;
@@ -403,7 +403,6 @@ in
shell.enable = lib.mkEnableOption "the zsh shell experience (starship prompt, bat/eza/zoxide)" // { default = true; };
keys.enable = lib.mkEnableOption "the SSH + GPG agent (gpg-agent fronting SSH, pinentry-qt)" // { default = true; };
fastfetch.enable = lib.mkEnableOption "fastfetch system info fronted by the themed Nomarchy logo" // { default = true; };
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
displays.enable = lib.mkEnableOption "the nwg-displays interactive monitor arranger (a helper to find nomarchy.monitors values; the declarative config stays the source of truth)" // { default = true; };

View File

@@ -946,11 +946,10 @@ ${themeRows}
exec ${cfg.terminal} -e sudo nomarchy-snapshots ;;
doctor)
# Read-only health sheet in a floating, centered ghostty window
# (class matched by hyprland.nix windowrules). --gtk-single-instance
# =false forces a fresh window same pattern as nomarchy-calendar.
# Exit code doesn't matter; the sheet itself is the product.
exec ghostty --class=com.nomarchy.doctor --gtk-single-instance=false \
# Read-only health sheet in a floating, centered kitty window
# (class matched by hyprland.nix windowrules). Same pattern as
# nomarchy-calendar. Exit code doesn't matter; the sheet is the product.
exec kitty --class=com.nomarchy.doctor \
-e sh -c "nomarchy-doctor
printf '\nEnter to close.'; read -r _" ;;
@@ -1045,14 +1044,14 @@ ${themeRows}
whatchanged)
# Plain-language last rebuild (system + desktop nvd). Toast the
# one-liners; open a floating terminal for the full report when
# the user wants detail (same ghostty class pattern as Doctor).
# the user wants detail (same kitty class pattern as Doctor).
if ! command -v nomarchy-what-changed >/dev/null 2>&1; then
notify-send "What changed" "nomarchy-what-changed not on PATH (lifecycle package?)."
exit 0
fi
summary=$(nomarchy-what-changed --summary 2>/dev/null || true)
[ -n "$summary" ] && notify-send -a Nomarchy "What changed" "$summary"
exec ghostty --class=com.nomarchy.doctor --gtk-single-instance=false \
exec kitty --class=com.nomarchy.doctor \
-e sh -c "nomarchy-what-changed
printf '\nEnter to close.'; read -r _" ;;

View File

@@ -1,11 +1,11 @@
# Shell experience — zsh (the default login shell, set system-side) with
# autosuggestions + syntax highlighting, a themed starship prompt, and
# modern CLI tools wired in: bat (cat), eza (ls), zoxide (cd). bat uses
# the "ansi" theme so it follows the terminal palette (Ghostty is themed
# the "ansi" theme so it follows the terminal palette (Kitty is themed
# from the same JSON); starship is themed from the palette directly.
#
# home.shell.enableZshIntegration = true is the single lever that makes
# every integrating program (starship, eza, zoxide, ghostty, yazi) emit
# every integrating program (starship, eza, zoxide, kitty, yazi) emit
# its zsh hooks — no per-module flags needed.
{ config, lib, pkgs, ... }:
@@ -133,7 +133,7 @@ in
};
# bat: "ansi" follows the terminal's 16-color palette → tracks the
# active Nomarchy theme (Ghostty bakes it) with no per-theme config.
# active Nomarchy theme (Kitty bakes it) with no per-theme config.
programs.bat = {
enable = true;
config = {

View File

@@ -1,7 +1,7 @@
# Stylix — themes the long tail of applications (GTK, Qt, cursors,
# fonts) from the same theme-state.json that drives the live engine.
#
# Division of labour: the hot-reload trio (Hyprland, Waybar, Ghostty)
# Division of labour: the hot-reload trio (Hyprland, Waybar, Kitty)
# is owned by the Nomarchy engine and updates instantly; everything
# Stylix touches updates on the next home-manager switch. That is why
# autoEnable is off and the trio's Stylix targets stay disabled.

View File

@@ -6,7 +6,7 @@
#
# Theme changes are fully Home Manager managed: `nomarchy-theme-sync
# apply <theme>` writes the JSON and runs `home-manager switch`, baking
# everything (Hyprland, Waybar, Ghostty, btop, Stylix) into one
# everything (Hyprland, Waybar, Kitty, btop, Stylix) into one
# read-only generation. No runtime patching, no partial states; theme
# history is generation history.
#

View File

@@ -93,20 +93,15 @@ let
[ -n "$next" ] && powerprofilesctl set "$next"
'';
# Opens calcurse (a lightweight TUI calendar, month view by default) in a
# floating, centered ghostty window — bound to the Waybar clock's on-click.
# A distinct --class gives the window a matchable app-id for the
# float+center+size windowrule (hyprland.nix); --gtk-single-instance=false
# forces a fresh standalone window (ghostty defaults single-instance on).
# calcurse is installed with the bar (home.packages below); the gate is
# only for someone who force-removed it. ghostty is always installed
# (ghostty.nix), so it can be relied on for the --class window.
# Opens calcurse (lightweight TUI calendar) in a floating, centered kitty
# window — Waybar clock on-click. Distinct --class → hyprland.nix float
# rules. Kitty is always installed (kitty.nix).
calendarLauncher = pkgs.writeShellScriptBin "nomarchy-calendar" ''
if ! command -v calcurse >/dev/null 2>&1; then
notify-send "Calendar" "calcurse isn't installed (removed from home.packages?)." 2>/dev/null
exit 0
fi
exec ghostty --class=com.nomarchy.calendar --gtk-single-instance=false -e calcurse
exec kitty --class=com.nomarchy.calendar -e calcurse
'';
# VPN indicator — shows a shield when a NetworkManager VPN/WireGuard
@@ -213,7 +208,7 @@ let
# into clock + clock#date — one click surface for the calendar).
format = "{:%H:%M · %a %d %b}";
# Left-click → the calendar (nomarchy-calendar → calcurse in a floating
# ghostty). Tooltip is plain date/zone only — embedding {calendar}
# kitty). Tooltip is plain date/zone only — embedding {calendar}
# produced an empty popup on hardware (2026-07-10); month view is
# one click away.
on-click = "nomarchy-calendar";

View File

@@ -1,5 +1,5 @@
# yazi — the flagship file manager: a fast, keyboard-driven TUI that
# fits the distro's identity (Ghostty's Kitty-graphics previews, rofi
# fits the distro's identity (Kitty graphics previews, rofi
# menus, everything from one JSON). Themed from theme-state.json and
# shipped with a curated plugin set. The GUI half (Thunar, "open folder"
# handler) is nomarchy.system.fileManager on the system side.
@@ -92,7 +92,7 @@ in
# Theme from the palette. yazi merges this over its built-in theme,
# so only the accent-bearing UI is specified; everything else keeps
# yazi's defaults (which already follow Ghostty's ANSI colors).
# yazi's defaults (which already follow Kitty's ANSI colors).
theme = {
mgr = {
cwd = { fg = c.accent; };

View File

@@ -4,7 +4,7 @@
# nixosModules.nomarchy in flake.nix) and layer your machine specifics
# (bootloader, hostname, users, hardware) on top. Host concerns are
# deliberately NOT set here. Everything user-facing (Hyprland config,
# Waybar, Ghostty, theming) lives in modules/home.
# Waybar, Kitty, theming) lives in modules/home.
{ config, lib, pkgs, ... }:
let

View File

@@ -211,12 +211,9 @@ function toggles_menu() {
sleep 1
;;
"Terminal")
term=$(gum choose "ghostty" "kitty" "alacritty" "wezterm" "foot")
if [ -n "$term" ]; then
set_state "settings.terminal" "\"$term\""
echo "Terminal set to $term (requires rebuild)."
fi
sleep 1
echo "Kitty is Nomarchy's terminal (themed from theme-state)."
echo "Override nomarchy.terminal in home.nix only if you install another yourself."
sleep 2
;;
"Keyboard Layout")
layout=$(gum input --prompt "Enter keyboard layout (e.g. us, de, es): " --placeholder "$(get_state settings.keyboard.layout | tr -d '"')")

View File

@@ -15,7 +15,6 @@
, pciutils # lspci
, usbutils # lsusb (fingerprint-reader VID probe; sysfs is the fallback)
, btrfs-progs # inspect-internal map-swapfile (hibernation offset)
, mesa-demos # glxinfo — OpenGL probe for Ghostty floor (needs 4.3)
, xkeyboard_config # human-readable installed layout/variant catalog
# Baked metadata — what this installer installs and where it came from.
, templateDir # templates/downstream (home.nix, theme-state.json)
@@ -65,7 +64,6 @@ stdenvNoCC.mkDerivation {
--prefix PATH : ${lib.makeBinPath [
bash gum disko whois git python3
util-linux gptfdisk parted cryptsetup lvm2 pciutils usbutils btrfs-progs
mesa-demos
]} \
--set NOMARCHY_INSTALL_SHARE "$share" \
--set NOMARCHY_XKB_RULES ${xkeyboard_config}/share/X11/xkb/rules/base.lst \

View File

@@ -625,47 +625,6 @@ python3 "$SHARE/patch-template.py" "$FLAKE_DIR" <<PYJSON
}
PYJSON
# Ghostty requires OpenGL 4.3 (docs/REQUIREMENTS.md). On older GPUs (Intel
# HD 4000 / Ivy Bridge tops at 4.2) it cannot map a surface. Prefer Kitty
# as the default terminal when we can prove the floor is missing — written
# into theme-state.json so SUPER+Return works after first boot without a
# hand edit. Unknown probe → leave Ghostty (do not guess on headless VMs).
gl_ver=""
if command -v glxinfo >/dev/null 2>&1; then
gl_ver=$(
{ DISPLAY="${DISPLAY:-:0}" WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-}" \
glxinfo -B 2>/dev/null || glxinfo -B 2>/dev/null || true; } \
| sed -n 's/.*OpenGL version string: \([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' \
| head -1
)
fi
if [[ -n "$gl_ver" ]]; then
gl_major=${gl_ver%%.*}
gl_minor=${gl_ver#*.}
gl_minor=${gl_minor%%.*}
if (( gl_major < 4 || (gl_major == 4 && gl_minor < 3) )); then
info "OpenGL $gl_ver < 4.3 — default terminal → kitty (Ghostty needs 4.3)"
python3 - "$FLAKE_DIR/theme-state.json" <<'PY'
import json, sys
path = sys.argv[1]
with open(path, encoding="utf-8") as f:
state = json.load(f)
settings = state.setdefault("settings", {})
# Do not clobber an explicit user/template choice.
if not settings.get("terminal"):
settings["terminal"] = "kitty"
settings["terminalReason"] = "opengl-below-4.3"
with open(path, "w", encoding="utf-8") as f:
json.dump(state, f, indent=2)
f.write("\n")
PY
else
info "OpenGL $gl_ver ≥ 4.3 — keeping Ghostty as the default terminal"
fi
else
info "OpenGL version not probed (glxinfo unavailable or no display) — Ghostty stays default"
fi
# The flake.lock: composed offline — nomarchy is path-locked to the very
# source the ISO carries (original stays the forge URL, so a later
# `nix flake update` on the installed machine re-resolves normally).

View File

@@ -6,7 +6,7 @@ read purely by Home Manager via the nomarchy.stateFile option).
Theme changes are applied by Home Manager: this tool writes the new state
and runs `home-manager switch` (override with $NOMARCHY_REBUILD, or skip
with --no-switch). All app theming — Hyprland, Waybar, Ghostty, btop,
with --no-switch). All app theming — Hyprland, Waybar, Kitty, btop,
Stylix — is baked into the generation; nothing is patched at runtime.
The one runtime exception is the wallpaper: swww is imperative by nature,

View File

@@ -1,5 +1,5 @@
# Your user environment. The Nomarchy desktop (Hyprland, Waybar,
# Ghostty, theming engine, Stylix) comes from homeModules.nomarchy;
# Kitty, theming engine, Stylix) comes from homeModules.nomarchy;
# tune it via the nomarchy.* options, add your own packages and
# programs below.
#
@@ -14,10 +14,8 @@
nomarchy.keyboard.variant = "";
# ── Overrides (the desktop is on by default; tweak or opt out) ──────
# nomarchy.terminal = "kitty"; # swap the default terminal (installer
# # sets this via settings.terminal when
# # OpenGL < 4.3 — Ghostty needs 4.3)
# nomarchy.kitty.enable = true; # themed Kitty without making it default
# nomarchy.terminal = "kitty"; # default; only Kitty is shipped/themed
# nomarchy.kitty.enable = false; # keep the package, drop our config
# nomarchy.waybar.enable = false; # bring your own bar
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
# nomarchy.dockAudio.enable = false; # keep audio put when docking

View File

@@ -1,5 +1,5 @@
# V2 harness for the floating Doctor terminal (System Doctor /
# nomarchy-menu doctor → ghostty --class=com.nomarchy.doctor).
# nomarchy-menu doctor → kitty --class=com.nomarchy.doctor).
#
# Boots headless softGL Hyprland (same stack as theme-shot), launches the
# real menu path, then asserts via hyprctl that the window is floating
@@ -8,8 +8,8 @@
#
# nix build --impure -f tools/doctor-float.nix --no-link --print-out-paths
#
# Maintainer harness — not a checks.* gate (full desktop VM). Ghostty
# under softGL is best-effort (MEMORY); if the client never appears the
# Maintainer harness — not a checks.* gate (full desktop VM). Kitty under
# softGL is best-effort (MEMORY); if the client never appears the
# scripted float asserts fail loudly rather than claiming success.
let
flake = builtins.getFlake ("git+file://" + toString ../.);
@@ -82,7 +82,7 @@ pkgs.testers.runNixOSTest {
# Real product path: Waybar / System Doctor both call this.
machine.execute(f"{hy} dispatch exec nomarchy-menu doctor' >/dev/null 2>&1")
# Wait for the classed Ghostty client (softGL may be slow).
# Wait for the classed Kitty client (softGL may be slow).
def clients():
raw = machine.succeed(f"{hy} clients -j'").strip()
try:
@@ -104,17 +104,15 @@ pkgs.testers.runNixOSTest {
dump = machine.succeed(f"{hy} clients -j'")
assert doctor is not None, (
"no client with class com.nomarchy.doctor after nomarchy-menu doctor "
f"(Ghostty under softGL may have failed clients dump):\n{dump}"
f"(Kitty under softGL may have failed clients dump):\n{dump}"
)
assert doctor.get("floating") is True, (
f"doctor window is not floating: {json.dumps(doctor, indent=2)}"
)
# Product contract: float + center. Ghostty often keeps its default
# 800×600 even when a size rule is present (client geometry wins);
# the size rule remains as a best-effort hint. Assert center from
# the actual size so a smaller Ghostty window still counts.
# Product contract: float + center. Size rule is best-effort if the
# client geometry wins; assert center from the actual size.
at = doctor.get("at") or [0, 0]
size = doctor.get("size") or [0, 0]
w, h = int(size[0]), int(size[1])

View File

@@ -39,7 +39,7 @@ ACCEL_ARG=()
echo "Launching ISO: $ISO"
# virtio-vga-gl + gl=on gives the guest real OpenGL — Hyprland and
# Ghostty need it; without GL the session may fail to start.
# the session needs it; without GL Hyprland may fail to start.
exec qemu-system-x86_64 \
"${ACCEL_ARG[@]}" \
-m 4096 -smp 2 \

View File

@@ -1,7 +1,7 @@
# Themed-desktop capture harness (item 28 slice c) — boots the full
# desktop headlessly (software-GL Hyprland) at 1920x1080 and QMP-dumps
# screenshots into $out: desktop.png, menu.png (rofi root open), and
# btop.png (Ghostty running btop, when the terminal starts under softGL).
# btop.png (Kitty running btop, when the terminal starts under softGL).
# Also asserts nomarchy-doctor-status JSON (class:bad) — the harness
# seeds an untracked theme-state.json, so doctor always reports ✖.
# Maintainer tool, NOT a checks.* gate (a full-desktop VM is far too
@@ -91,13 +91,13 @@ pkgs.testers.runNixOSTest {
machine.execute(hy + " exec nomarchy-menu' >/dev/null 2>&1")
machine.sleep(8)
machine.screenshot("menu")
# Close menu, launch btop in Ghostty for the per-theme btop.theme shot.
# softGL may fail to start Ghostty btop.png is best-effort then; the
# Close menu, launch btop in Kitty for the per-theme btop.theme shot.
# softGL may still fail to start a GPU terminal btop.png is best-effort;
# file assertions above still prove the theme is baked into the guest.
machine.execute("su - nomarchy -c 'pkill -x rofi' >/dev/null 2>&1 || true")
machine.sleep(1)
machine.execute(
hy + " exec ghostty --gtk-single-instance=false -e btop' >/dev/null 2>&1"
hy + " exec kitty -e btop' >/dev/null 2>&1"
)
machine.sleep(12)
machine.screenshot("btop")