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: │ │ Home Manager bakes EVERYTHING into one read-only generation: │
│ Hyprland (colors/gaps/borders) Waybar (palette or whole-swap) │ │ 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 │ │ 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 │ ├── stylix.nix # GTK/Qt/cursors/fonts from the same JSON
│ ├── hyprland.nix # all JSON-driven │ ├── hyprland.nix # all JSON-driven
│ ├── waybar.nix │ ├── waybar.nix
│ ├── ghostty.nix │ ├── kitty.nix
│ ├── btop.nix │ ├── btop.nix
│ ├── rofi.nix # launcher + nomarchy-menu (calc, emoji, clip…) │ ├── rofi.nix # launcher + nomarchy-menu (calc, emoji, clip…)
│ ├── keybinds.nix # single source: Hyprland binds + SUPER+? sheet │ ├── keybinds.nix # single source: Hyprland binds + SUPER+? sheet
@@ -103,8 +103,8 @@ probably shouldn't exist.
## 2. Try it first (live ISO) ## 2. Try it first (live ISO)
**Before you install:** check **[docs/REQUIREMENTS.md](docs/REQUIREMENTS.md)** **Before you install:** check **[docs/REQUIREMENTS.md](docs/REQUIREMENTS.md)**
(UEFI x86_64, **OpenGL 4.3** for the default terminal, disk planning for the (UEFI x86_64, disk planning for the Nix store + BTRFS snapshots — 128GiB is
Nix store + BTRFS snapshots — 128GiB is the comfortable floor). the comfortable floor).
Boot the full desktop from a USB stick or VM without installing anything: 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 | | Option | Default | Purpose |
|---|---|---| |---|---|---|
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json | | `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.terminal` | `"kitty"` | Terminal for keybinds and `$TERMINAL` (Kitty is the only shipped/themed emulator) |
| `nomarchy.kitty.enable` | `false` | Themed Kitty (also auto-on when terminal is kitty) | | `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.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.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 | | `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.yazi.enable` | `true` | yazi TUI file manager, themed + curated plugins |
| `nomarchy.osd.enable` | `true` | swayosd on-screen display for volume/brightness/mute | | `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.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.btop.enable` | `true` | btop with per-theme colors |
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming | | `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo | | `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 `nomarchy-theme-sync apply <theme>` merges the preset into the JSON and runs
`home-manager switch` (override the command with `$NOMARCHY_REBUILD`, or pass `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 btop, and — via Stylix, mapped onto base16 roles — GTK, Qt, cursors and
fonts. No runtime patching means no partial states, and `home-manager fonts. No runtime patching means no partial states, and `home-manager
generations` is also your theme history. Waybar even restyles in place: it 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 ### 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 Bernardo, real installs 2026-07-1314 (photos of the install end screens and
post-boot sessions). Preserve separation: the installer bake failure, the post-boot sessions). Preserve separation: the installer bake failure and the
flake pin, and the Ghostty GL floor are different root causes even when they flake pin are different root causes even when they show up on the same machine.
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 ### 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 mime defaults resolve to `chromium-browser.desktop` (and the intended live-ISO
browser posture is explicit). 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 ### 98. Boreal: button text renders black and is difficult to read
Audit GTK button foreground/background contrast under Boreal, including the 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 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: 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 theme JSON), not stylix's default. **Boreal — the default theme and the base
state — is `GeistMono Nerd Font`**; the other 23 themes are `JetBrainsMono state — is `GeistMono Nerd Font`**; the other 23 themes are `JetBrainsMono
Nerd Font`. Any answer must hold for both. 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 ergonomic writer for the flake. Where a toggle can take effect without a
rebuild, it must (`--no-switch` + flip the running service). rebuild, it must (`--no-switch` + flip the running service).
4. **Beautiful.** One JSON themes the entire desktop coherently — Hyprland, 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 surface follows the palette. Informative, self-gating Waybar modules
(they hide when irrelevant). No unthemed corner survives contact with (they hide when irrelevant). No unthemed corner survives contact with
the theme switcher. the theme switcher.

View File

@@ -436,12 +436,9 @@ the **T14s** (webcam case).
**without** running `home-manager switch` by hand. **Fail** = still **without** running `home-manager switch` by hand. **Fail** = still
need the recovery one-liner, or GTK/nm-applet still wrong until a need the recovery one-liner, or GTK/nm-applet still wrong until a
manual switch (then the bake is still incomplete). manual switch (then the bake is still incomplete).
- [ ] **#95 themed Kitty fallback on Acer M5-481T** — after install from an - [ ] **#95 Kitty-only terminal on Acer M5-481T** — after rebuild/install
ISO that probes GL &lt; 4.3 (or set `settings.terminal = "kitty"` + from main: SUPER+Return opens **themed Kitty**; System Doctor opens
`nomarchy-home`): SUPER+Return opens **Kitty** with Boreal (or current a floating classed Kitty window. No Ghostty on PATH required.
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.
- [ ] **#124 flake pin after main-ISO install** — on a machine installed - [ ] **#124 flake pin after main-ISO install** — on a machine installed
from a **main-built** ISO (post-fix): `~/.nomarchy/flake.nix` from a **main-built** ISO (post-fix): `~/.nomarchy/flake.nix`
nomarchy input must not re-resolve to a lagging `v1` that lacks 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. - **Task:** Bernardo: when GL &lt; 4.3 automatically add kitty — and theme it.
- **Did:** `modules/home/kitty.nix` themes Kitty from theme-state (same - **Did:** `modules/home/kitty.nix` themes Kitty from theme-state (same
palette/font/opacity as Ghostty); enables when `nomarchy.terminal` is 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` - **Doctor float V2:** `THEME=<slug> nix build --impure -f tools/doctor-float.nix`
— softGL Hyprland, `nomarchy-menu doctor`, asserts — softGL Hyprland, `nomarchy-menu doctor`, asserts
`class=com.nomarchy.doctor` + `floating` + centered midpoints + `class=com.nomarchy.doctor` + `floating` + centered midpoints +
screenshots. Ghostty *does* start here under softGL (classed one-shot); screenshots (Kitty `--class=…`). SoftGL may still struggle with a GPU
size often stays Ghosttys default 800×600 (client geometry wins over terminal; size can ignore percent windowrules if client geometry wins.
the percent `size` windowrule). - **theme-shot softGL may not start Kitty** — `btop.png` is best-effort
- **theme-shot softGL cannot start Ghostty** — `btop.png` is best-effort
(usually identical to desktop). Guest asserts on (usually identical to desktop). Guest asserts on
`~/.config/btop/themes/nomarchy.theme` prove baking; the TUI look is `~/.config/btop/themes/nomarchy.theme` prove baking; the TUI look is
hardware/GL tier (HARDWARE-QUEUE). Doctor float is the counter-example hardware/GL tier (HARDWARE-QUEUE).
that a *classed* one-shot Ghostty can still map under softGL.
- **Waybar `custom/doctor` tripwire:** status helper must invoke - **Waybar `custom/doctor` tripwire:** status helper must invoke
`nomarchy-doctor` by **absolute store path** (waybar's env can miss `nomarchy-doctor` by **absolute store path** (waybar's env can miss
system PATH → `command -v … || exit 0` self-hides forever); empty 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 (`LIBGL_ALWAYS_SOFTWARE` on virtio-gpu) + `machine.screenshot()` QMP
dump — prototyped 2026-06-19, kept as the fallback for theme previews dump — prototyped 2026-06-19, kept as the fallback for theme previews
(§ Visual theme picker). (§ Visual theme picker).
- Hyprland/Ghostty need guest GL (`virtio-vga-gl`, `gl=on`) in - Hyprland needs guest GL (`virtio-vga-gl`, `gl=on`) in interactive QEMU
interactive QEMU or the session won't start; black screen ≈ missing GL or the session won't start; black screen ≈ missing GL
(docs/TESTING.md § gotchas). (docs/TESTING.md § gotchas). Kitty is the sole terminal (no Ghostty).
- No KVM = slow, not broken; don't read slowness as failure. - No KVM = slow, not broken; don't read slowness as failure.
## Known-broken / watchlist ## Known-broken / watchlist

View File

@@ -20,7 +20,7 @@ consumes the palette from the state JSON, never a side file.
## Design responsibilities ## Design responsibilities
1. **Holistic design:** a theme spans Hyprland (borders, shadows, 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. one coherent identity, no unthemed corner.
2. **Color theory:** create or adapt advanced palettes. Draw inspiration 2. **Color theory:** create or adapt advanced palettes. Draw inspiration
from established aesthetics (Everforest, Nord, Gruvbox) or r/unixporn 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 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 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: Stylix at once:
```sh ```sh
@@ -98,9 +98,8 @@ in your `home.nix` wins — no `mkForce` needed:
animations.enabled = false; animations.enabled = false;
}; };
programs.ghostty.settings = { programs.kitty.settings = {
window-padding-x = 4; # was 12 window_padding_width = 4; # was 12
window-decoration = true;
}; };
} }
``` ```

View File

@@ -2,7 +2,7 @@
What Nomarchy expects of a machine. This is a **living floor**, not a What Nomarchy expects of a machine. This is a **living floor**, not a
marketing sheet — numbers come from measured installs and known software 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. this file in the same change.
Related: [HARDWARE.md](HARDWARE.md) (profiles/drivers), Related: [HARDWARE.md](HARDWARE.md) (profiles/drivers),
@@ -22,39 +22,22 @@ Related: [HARDWARE.md](HARDWARE.md) (profiles/drivers),
## Graphics (default desktop) ## Graphics (default desktop)
The default terminal is **Ghostty**, which requires **OpenGL 4.3** (desktop The sole terminal is **Kitty** (GPU-accelerated OpenGL, themed from
profile). That is a **GPU generation** limit, not a “driver not installed” theme-state). It runs on older integrated GPUs that reject Ghosttys OpenGL
problem: **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 | | Generation (examples) | Notes |
|-----------------------|---------------------------|-----------------| |-----------------------|--------|
| Ivy Bridge / HD 4000 (e.g. **Acer Aspire M5-481T**, ~2012) | **4.2** | **Does not start** (`OpenGLOutdated`) | | Ivy Bridge / HD 4000 (~2012) | Supported with Kitty (verified path on Acer M5-481T) |
| Haswell and newer Intel iGPU, most AMD GCN+, discrete GPUs of the last decade | ≥ 4.3 | OK | | Haswell+ Intel, modern AMD, discrete GPUs | Supported |
| Dell XPS 9350 (Skylake) | ≥ 4.3 | OK (verified 2026-07) | | SoftGL / virtio-gpu VMs | Hyprland needs GL for the session; Kitty is best-effort under softGL |
**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`).
Other Wayland clients vary; Hyprland itself is usually fine on these GPUs. 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 | | Machine | Role |
|---------|------| |---------|------|
| **Acer Aspire M5-481T** (~2012, Intel HD 4000, OpenGL 4.2) | Ghostty floor (#95); install bake / old-HW QA | | **Acer Aspire M5-481T** (~2012, Intel HD 4000) | Old-HW QA; drove Kitty-only terminal (#95) |
| **Dell XPS 9350** (Skylake) | Install bake (#123); Ghostty OK | | **Dell XPS 9350** (Skylake) | Install bake (#123) |
| AMD dev box / Latitude / T14s | Ongoing V3 (HARDWARE-QUEUE) | | AMD dev box / Latitude / T14s | Ongoing V3 (HARDWARE-QUEUE) |
When you install on something older or smaller than the table, file what 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 | | 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 **#120** | Lighter netinstall ISO (download size ≠ installed size) |
| BACKLOG **#123** | Installer HM pre-activate (first-boot polish) | | BACKLOG **#123** | Installer HM pre-activate (first-boot polish) |
| BACKLOG **#124** | Flake pin vs main/v1 lag after install | | 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 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 name the missing entry. **V3 pending** — that the apps *launch* needs real
hardware (HARDWARE-QUEUE, Acer M5-481T). hardware (HARDWARE-QUEUE, Acer M5-481T).
- ✓ **Kitty fallback when OpenGL &lt; 4.3 (#95 partial):** Ghostty needs GL 4.3; - ✓ **Kitty is the only terminal (#95 complete):** Ghosttys OpenGL 4.3 floor
Ivy Bridge HD 4000 tops at 4.2 (Acer M5-481T). Installer probes `glxinfo` broke SUPER+Return (and classed doctor/calendar windows) on Ivy Bridge
and writes `settings.terminal = "kitty"` when below the floor; `kitty.nix` HD 4000 (Acer M5-481T). Maintaining two terminals was pure complexity.
themes Kitty from the same theme-state as Ghostty (ANSI, mono font, **Kitty only:** always installed, themed from theme-state (ANSI/font/opacity),
opacity). Default machines stay Ghostty-only in the HM closure. V3 on Acer default `$TERMINAL` / SUPER+Return, doctor + calendar + what-changed use
still needed; doctor/calendar still invoke Ghostty by class. `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 - ✓ **Mime defaults must name a present .desktop (#119):** same bug class as
#94, one key over. `text/plain` pointed at `code.desktop` (vscode), which #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 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 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` `/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. session may not start.
### What the live environment gives you ### 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 | | 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 | | 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 | | 4 | `btop` in the terminal is themed | per-theme asset baking |
| 5 | `nomarchy-theme-sync list` prints 24 presets | package, baked themes dir | | 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 | | 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 # ISO is the desktop, so re-enable what it strips. Above all
# fontconfig (upstream forces it off at mkOverride 500): without it # fontconfig (upstream forces it off at mkOverride 500): without it
# no configured family resolves — Waybar icons render as tofu and # no configured family resolves — Waybar icons render as tofu and
# Ghostty silently falls back to the wrong font (seen on the # Kitty silently falls back to the wrong font (seen on the
# Latitude 5410). Normal priority (100) beats the override. # Latitude 5410 with Ghostty; same fontconfig footgun). Normal priority
# (100) beats the override.
fonts.fontconfig.enable = true; fonts.fontconfig.enable = true;
# No boot splash on the install medium: the installer ISO boots its # 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 ./stylix.nix # GTK/Qt/cursor/fonts from the same JSON
./hyprland.nix ./hyprland.nix
./waybar.nix ./waybar.nix
./ghostty.nix ./kitty.nix # sole terminal (themed); doctor/calendar/--class load-bearing
./kitty.nix # themed fallback when Ghostty cannot run (OpenGL < 4.3)
./btop.nix ./btop.nix
./rofi.nix # launcher theming + the nomarchy-menu dispatcher ./rofi.nix # launcher theming + the nomarchy-menu dispatcher
./swaync.nix # notification daemon, themed from the same JSON ./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)?)$" "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)?)$" "center 1, match:class (?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$"
# Calendar popup (item 42): the Waybar clock's on-click runs # Calendar popup (item 42): nomarchy-calendar → calcurse in a
# nomarchy-calendar → calcurse in a ghostty window tagged with a # kitty window tagged with a distinct --class, so it floats centered.
# distinct --class, so it floats centered instead of tiling.
"float 1, match:class ^(com\\.nomarchy\\.calendar)$" "float 1, match:class ^(com\\.nomarchy\\.calendar)$"
"size 60% 65%, match:class ^(com\\.nomarchy\\.calendar)$" "size 60% 65%, match:class ^(com\\.nomarchy\\.calendar)$"
"center 1, match:class ^(com\\.nomarchy\\.calendar)$" "center 1, match:class ^(com\\.nomarchy\\.calendar)$"
# Doctor sheet (System Doctor / Waybar custom/doctor click): # 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)$" "float 1, match:class ^(com\\.nomarchy\\.doctor)$"
"size 55% 70%, match:class ^(com\\.nomarchy\\.doctor)$" "size 55% 70%, match:class ^(com\\.nomarchy\\.doctor)$"
"center 1, 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 # Kitty — Nomarchy's only terminal, themed from theme-state.json.
# older GPUs, e.g. Intel HD 4000). Themed from the same theme-state.json # Colors, fonts and the full 16-color ANSI palette are baked from the
# as Ghostty so a machine that needs the fallback still looks like # JSON at eval time (same contract Ghostty used to have). Always
# Nomarchy. Enabled when nomarchy.terminal is "kitty" (installer sets # installed: SUPER+Return, SUPER+E, doctor, calendar, and $TERMINAL
# that after a GL probe) or when nomarchy.kitty.enable is forced on. # all depend on it.
{ config, lib, ... }: { config, lib, ... }:
let let
t = config.nomarchy.theme; t = config.nomarchy.theme;
c = t.colors; 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 ( colorSettings = lib.listToAttrs (
lib.imap0 (i: color: { lib.imap0 (i: color: {
name = "color${toString i}"; name = "color${toString i}";
@@ -29,35 +16,37 @@ let
); );
in in
{ {
config = lib.mkIf enabled { # Kitty is ALWAYS installed. `nomarchy.kitty.enable` gates only whether
programs.kitty = { # Nomarchy's theming/config is applied — a user can keep kitty but drop
enable = true; # our config; they cannot remove kitty itself without breaking the
shellIntegration.enableBashIntegration = true; # desktop's load-bearing classed windows.
shellIntegration.enableZshIntegration = true; programs.kitty = {
enable = true;
shellIntegration.enableBashIntegration = true;
shellIntegration.enableZshIntegration = true;
font = { font = lib.mkIf config.nomarchy.kitty.enable {
name = t.fonts.mono; name = t.fonts.mono;
size = t.fonts.size; 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;
}; };
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 ──────────────────────────────────────────────── # ── Preferences ────────────────────────────────────────────────
terminal = lib.mkOption { terminal = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = config.nomarchy.settings.terminal or "ghostty"; default = config.nomarchy.settings.terminal or "kitty";
example = "kitty"; example = "kitty";
description = '' description = ''
Terminal emulator command, used by keybinds and `$TERMINAL`. Terminal emulator command for keybinds and `$TERMINAL`. Nomarchy
Default is Ghostty. On GPUs below OpenGL 4.3 the installer writes ships and themes **Kitty only** (sole supported terminal works
`settings.terminal = "kitty"` so SUPER+Return still works (Ghostty on older GPUs that Ghostty's OpenGL 4.3 floor rejected). Override
needs 4.3; see docs/REQUIREMENTS.md). Set explicitly to 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 { keyboard.layout = lib.mkOption {
type = lib.types.str; type = lib.types.str;
@@ -403,7 +403,6 @@ in
shell.enable = lib.mkEnableOption "the zsh shell experience (starship prompt, bat/eza/zoxide)" // { default = true; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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 ;; exec ${cfg.terminal} -e sudo nomarchy-snapshots ;;
doctor) doctor)
# Read-only health sheet in a floating, centered ghostty window # Read-only health sheet in a floating, centered kitty window
# (class matched by hyprland.nix windowrules). --gtk-single-instance # (class matched by hyprland.nix windowrules). Same pattern as
# =false forces a fresh window same pattern as nomarchy-calendar. # nomarchy-calendar. Exit code doesn't matter; the sheet is the product.
# Exit code doesn't matter; the sheet itself is the product. exec kitty --class=com.nomarchy.doctor \
exec ghostty --class=com.nomarchy.doctor --gtk-single-instance=false \
-e sh -c "nomarchy-doctor -e sh -c "nomarchy-doctor
printf '\nEnter to close.'; read -r _" ;; printf '\nEnter to close.'; read -r _" ;;
@@ -1045,14 +1044,14 @@ ${themeRows}
whatchanged) whatchanged)
# Plain-language last rebuild (system + desktop nvd). Toast the # Plain-language last rebuild (system + desktop nvd). Toast the
# one-liners; open a floating terminal for the full report when # 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 if ! command -v nomarchy-what-changed >/dev/null 2>&1; then
notify-send "What changed" "nomarchy-what-changed not on PATH (lifecycle package?)." notify-send "What changed" "nomarchy-what-changed not on PATH (lifecycle package?)."
exit 0 exit 0
fi fi
summary=$(nomarchy-what-changed --summary 2>/dev/null || true) summary=$(nomarchy-what-changed --summary 2>/dev/null || true)
[ -n "$summary" ] && notify-send -a Nomarchy "What changed" "$summary" [ -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 -e sh -c "nomarchy-what-changed
printf '\nEnter to close.'; read -r _" ;; printf '\nEnter to close.'; read -r _" ;;

View File

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

View File

@@ -1,7 +1,7 @@
# Stylix — themes the long tail of applications (GTK, Qt, cursors, # Stylix — themes the long tail of applications (GTK, Qt, cursors,
# fonts) from the same theme-state.json that drives the live engine. # 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 # is owned by the Nomarchy engine and updates instantly; everything
# Stylix touches updates on the next home-manager switch. That is why # Stylix touches updates on the next home-manager switch. That is why
# autoEnable is off and the trio's Stylix targets stay disabled. # 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 # Theme changes are fully Home Manager managed: `nomarchy-theme-sync
# apply <theme>` writes the JSON and runs `home-manager switch`, baking # 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 # read-only generation. No runtime patching, no partial states; theme
# history is generation history. # history is generation history.
# #

View File

@@ -93,20 +93,15 @@ let
[ -n "$next" ] && powerprofilesctl set "$next" [ -n "$next" ] && powerprofilesctl set "$next"
''; '';
# Opens calcurse (a lightweight TUI calendar, month view by default) in a # Opens calcurse (lightweight TUI calendar) in a floating, centered kitty
# floating, centered ghostty window — bound to the Waybar clock's on-click. # window — Waybar clock on-click. Distinct --class → hyprland.nix float
# A distinct --class gives the window a matchable app-id for the # rules. Kitty is always installed (kitty.nix).
# 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.
calendarLauncher = pkgs.writeShellScriptBin "nomarchy-calendar" '' calendarLauncher = pkgs.writeShellScriptBin "nomarchy-calendar" ''
if ! command -v calcurse >/dev/null 2>&1; then if ! command -v calcurse >/dev/null 2>&1; then
notify-send "Calendar" "calcurse isn't installed (removed from home.packages?)." 2>/dev/null notify-send "Calendar" "calcurse isn't installed (removed from home.packages?)." 2>/dev/null
exit 0 exit 0
fi 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 # 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). # into clock + clock#date — one click surface for the calendar).
format = "{:%H:%M · %a %d %b}"; format = "{:%H:%M · %a %d %b}";
# Left-click → the calendar (nomarchy-calendar → calcurse in a floating # 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 # produced an empty popup on hardware (2026-07-10); month view is
# one click away. # one click away.
on-click = "nomarchy-calendar"; on-click = "nomarchy-calendar";

View File

@@ -1,5 +1,5 @@
# yazi — the flagship file manager: a fast, keyboard-driven TUI that # 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 # menus, everything from one JSON). Themed from theme-state.json and
# shipped with a curated plugin set. The GUI half (Thunar, "open folder" # shipped with a curated plugin set. The GUI half (Thunar, "open folder"
# handler) is nomarchy.system.fileManager on the system side. # 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, # Theme from the palette. yazi merges this over its built-in theme,
# so only the accent-bearing UI is specified; everything else keeps # 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 = { theme = {
mgr = { mgr = {
cwd = { fg = c.accent; }; cwd = { fg = c.accent; };

View File

@@ -4,7 +4,7 @@
# nixosModules.nomarchy in flake.nix) and layer your machine specifics # nixosModules.nomarchy in flake.nix) and layer your machine specifics
# (bootloader, hostname, users, hardware) on top. Host concerns are # (bootloader, hostname, users, hardware) on top. Host concerns are
# deliberately NOT set here. Everything user-facing (Hyprland config, # 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, ... }: { config, lib, pkgs, ... }:
let let

View File

@@ -211,12 +211,9 @@ function toggles_menu() {
sleep 1 sleep 1
;; ;;
"Terminal") "Terminal")
term=$(gum choose "ghostty" "kitty" "alacritty" "wezterm" "foot") echo "Kitty is Nomarchy's terminal (themed from theme-state)."
if [ -n "$term" ]; then echo "Override nomarchy.terminal in home.nix only if you install another yourself."
set_state "settings.terminal" "\"$term\"" sleep 2
echo "Terminal set to $term (requires rebuild)."
fi
sleep 1
;; ;;
"Keyboard Layout") "Keyboard Layout")
layout=$(gum input --prompt "Enter keyboard layout (e.g. us, de, es): " --placeholder "$(get_state settings.keyboard.layout | tr -d '"')") 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 , pciutils # lspci
, usbutils # lsusb (fingerprint-reader VID probe; sysfs is the fallback) , usbutils # lsusb (fingerprint-reader VID probe; sysfs is the fallback)
, btrfs-progs # inspect-internal map-swapfile (hibernation offset) , 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 , xkeyboard_config # human-readable installed layout/variant catalog
# Baked metadata — what this installer installs and where it came from. # Baked metadata — what this installer installs and where it came from.
, templateDir # templates/downstream (home.nix, theme-state.json) , templateDir # templates/downstream (home.nix, theme-state.json)
@@ -65,7 +64,6 @@ stdenvNoCC.mkDerivation {
--prefix PATH : ${lib.makeBinPath [ --prefix PATH : ${lib.makeBinPath [
bash gum disko whois git python3 bash gum disko whois git python3
util-linux gptfdisk parted cryptsetup lvm2 pciutils usbutils btrfs-progs util-linux gptfdisk parted cryptsetup lvm2 pciutils usbutils btrfs-progs
mesa-demos
]} \ ]} \
--set NOMARCHY_INSTALL_SHARE "$share" \ --set NOMARCHY_INSTALL_SHARE "$share" \
--set NOMARCHY_XKB_RULES ${xkeyboard_config}/share/X11/xkb/rules/base.lst \ --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 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 # The flake.lock: composed offline — nomarchy is path-locked to the very
# source the ISO carries (original stays the forge URL, so a later # source the ISO carries (original stays the forge URL, so a later
# `nix flake update` on the installed machine re-resolves normally). # `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 Theme changes are applied by Home Manager: this tool writes the new state
and runs `home-manager switch` (override with $NOMARCHY_REBUILD, or skip 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. Stylix — is baked into the generation; nothing is patched at runtime.
The one runtime exception is the wallpaper: swww is imperative by nature, 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, # 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 # tune it via the nomarchy.* options, add your own packages and
# programs below. # programs below.
# #
@@ -14,10 +14,8 @@
nomarchy.keyboard.variant = ""; nomarchy.keyboard.variant = "";
# ── Overrides (the desktop is on by default; tweak or opt out) ────── # ── Overrides (the desktop is on by default; tweak or opt out) ──────
# nomarchy.terminal = "kitty"; # swap the default terminal (installer # nomarchy.terminal = "kitty"; # default; only Kitty is shipped/themed
# # sets this via settings.terminal when # nomarchy.kitty.enable = false; # keep the package, drop our config
# # OpenGL < 4.3 — Ghostty needs 4.3)
# nomarchy.kitty.enable = true; # themed Kitty without making it default
# nomarchy.waybar.enable = false; # bring your own bar # nomarchy.waybar.enable = false; # bring your own bar
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming # nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
# nomarchy.dockAudio.enable = false; # keep audio put when docking # nomarchy.dockAudio.enable = false; # keep audio put when docking

View File

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

View File

@@ -39,7 +39,7 @@ ACCEL_ARG=()
echo "Launching ISO: $ISO" echo "Launching ISO: $ISO"
# virtio-vga-gl + gl=on gives the guest real OpenGL — Hyprland and # 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 \ exec qemu-system-x86_64 \
"${ACCEL_ARG[@]}" \ "${ACCEL_ARG[@]}" \
-m 4096 -smp 2 \ -m 4096 -smp 2 \

View File

@@ -1,7 +1,7 @@
# Themed-desktop capture harness (item 28 slice c) — boots the full # Themed-desktop capture harness (item 28 slice c) — boots the full
# desktop headlessly (software-GL Hyprland) at 1920x1080 and QMP-dumps # desktop headlessly (software-GL Hyprland) at 1920x1080 and QMP-dumps
# screenshots into $out: desktop.png, menu.png (rofi root open), and # 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 # Also asserts nomarchy-doctor-status JSON (class:bad) — the harness
# seeds an untracked theme-state.json, so doctor always reports ✖. # seeds an untracked theme-state.json, so doctor always reports ✖.
# Maintainer tool, NOT a checks.* gate (a full-desktop VM is far too # 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.execute(hy + " exec nomarchy-menu' >/dev/null 2>&1")
machine.sleep(8) machine.sleep(8)
machine.screenshot("menu") machine.screenshot("menu")
# Close menu, launch btop in Ghostty for the per-theme btop.theme shot. # Close menu, launch btop in Kitty for the per-theme btop.theme shot.
# softGL may fail to start Ghostty btop.png is best-effort then; the # 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. # 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.execute("su - nomarchy -c 'pkill -x rofi' >/dev/null 2>&1 || true")
machine.sleep(1) machine.sleep(1)
machine.execute( 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.sleep(12)
machine.screenshot("btop") machine.screenshot("btop")