aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/home/desktop-apps.nix28
-rw-r--r--modules/nixos/common.nix13
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/.openspec.yaml2
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/design.md51
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/proposal.md30
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/desktop-applications/spec.md21
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/gnome-desktop/spec.md12
-rw-r--r--openspec/changes/add-ghostty-gnome-tweaks-dark-mode/tasks.md15
8 files changed, 166 insertions, 6 deletions
diff --git a/modules/home/desktop-apps.nix b/modules/home/desktop-apps.nix
index 882ce34..a565c18 100644
--- a/modules/home/desktop-apps.nix
+++ b/modules/home/desktop-apps.nix
@@ -1,10 +1,28 @@
1{ pkgs, lib, ... }: 1{
2 pkgs,
3 lib,
4 osConfig ? null,
5 ...
6}:
2let 7let
3 crossPlatformApps = [ pkgs.slack pkgs.discord pkgs.spotify pkgs.firefox pkgs.bitwarden-desktop ]; 8 crossPlatformApps = [
9 pkgs.slack
10 pkgs.discord
11 pkgs.spotify
12 pkgs.firefox
13 pkgs.bitwarden-desktop
14 pkgs.ghostty
15 ];
4 linuxOnlyApps = lib.optional pkgs.stdenv.hostPlatform.isLinux pkgs.teams-for-linux; 16 linuxOnlyApps = lib.optional pkgs.stdenv.hostPlatform.isLinux pkgs.teams-for-linux;
5 candidateApps = crossPlatformApps ++ linuxOnlyApps; 17 # GNOME Tweaks only makes sense where GNOME is actually enabled, which this
18 # flake only does at the NixOS level (modules/nixos/common.nix) - not on
19 # standalone, non-NixOS activations of this shared profile. osConfig is the
20 # full NixOS config and is only present when home-manager is integrated
21 # into a NixOS system; it's absent for standalone `home-manager switch`.
22 gnomeOnlyApps = lib.optional (osConfig.services.desktopManager.gnome.enable or false
23 ) pkgs.gnome-tweaks;
24 candidateApps = crossPlatformApps ++ linuxOnlyApps ++ gnomeOnlyApps;
6in 25in
7{ 26{
8 home.packages = 27 home.packages = builtins.filter (lib.meta.availableOn pkgs.stdenv.hostPlatform) candidateApps;
9 builtins.filter (lib.meta.availableOn pkgs.stdenv.hostPlatform) candidateApps;
10} 28}
diff --git a/modules/nixos/common.nix b/modules/nixos/common.nix
index 1b34e4e..a219850 100644
--- a/modules/nixos/common.nix
+++ b/modules/nixos/common.nix
@@ -1,6 +1,9 @@
1{ pkgs, lib, ... }: 1{ pkgs, lib, ... }:
2{ 2{
3 nix.settings.experimental-features = [ "nix-command" "flakes" ]; 3 nix.settings.experimental-features = [
4 "nix-command"
5 "flakes"
6 ];
4 7
5 nix.gc = { 8 nix.gc = {
6 automatic = true; 9 automatic = true;
@@ -43,6 +46,14 @@
43 services.displayManager.gdm.enable = true; 46 services.displayManager.gdm.enable = true;
44 services.desktopManager.gnome.enable = true; 47 services.desktopManager.gnome.enable = true;
45 48
49 # Defaults GNOME to dark mode without locking it - GNOME Settings'
50 # Appearance toggle still writes to the user's own dconf database, which
51 # is searched before this default database.
52 programs.dconf.enable = true;
53 programs.dconf.profiles.user.databases = [
54 { settings."org/gnome/desktop/interface".color-scheme = "prefer-dark"; }
55 ];
56
46 networking.networkmanager.enable = true; 57 networking.networkmanager.enable = true;
47 58
48 services.pipewire = { 59 services.pipewire = {
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/.openspec.yaml b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/.openspec.yaml
new file mode 100644
index 0000000..75289e4
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/.openspec.yaml
@@ -0,0 +1,2 @@
1schema: spec-driven
2created: 2026-09-24
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/design.md b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/design.md
new file mode 100644
index 0000000..72262d1
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/design.md
@@ -0,0 +1,51 @@
1## Context
2
3See proposal.md - Why. This section covers two decisions with real alternatives: how to make GNOME default to dark mode system-wide, as a *default* rather than an enforced policy; and how to scope GNOME Tweaks to only the profile activations where GNOME actually exists.
4
5`modules/nixos/common.nix` already sets `services.desktopManager.gnome.enable = true;` for every NixOS host (see `openspec/specs/gnome-desktop/spec.md`), which transitively enables NixOS's dconf module (`programs.dconf`, defined in `nixos/modules/programs/dconf.nix` in the pinned `nixos-unstable` nixpkgs). That module already ships the primitive needed here: `programs.dconf.profiles.<name>.databases`, a list of dconf keyfile databases merged into the named profile (`user` by default).
6
7Key mechanics confirmed by reading that module's source:
8- A profile's databases are searched top-to-bottom, first match wins, *except* the live, user-writable dconf database (`user-db:user`), which is prepended automatically (`enableUserDb = true` by default) and is therefore always searched **before** any `databases` entries.
9- This means a value written into `programs.dconf.profiles.user.databases[].settings` acts as a fallback: it only applies where the user hasn't already written their own value via `dconf write` / GNOME Settings. No `locks` entry is needed (and none is added) — adding one would make the value mandatory instead of a default, which is not what was asked for ("enabled by default", not "enforced").
10
11`modules/home/desktop-apps.nix` (and the rest of `modules/home/`) is consumed two ways: by every NixOS host, via `lib/mkNixos.nix`'s home-manager integration; and by the standalone, non-NixOS `homeConfigurations."tom@linux"`/`"tom@darwin"`, via `lib/mkHome.nix` (see README: "any Linux now"). Only the former actually has GNOME enabled — the latter is a generic Linux/macOS home-manager profile with no GNOME involved at all. Confirmed by reading the locked `home-manager` input's `nixos/common.nix` (the module backing `inputs.home-manager.nixosModules.home-manager`): the NixOS integration passes each user's home-manager modules an `osConfig` specialArg set to the full NixOS `config`. That specialArg exists only when home-manager is evaluated as part of a NixOS (or nix-darwin) system; `lib/mkHome.nix`'s standalone `homeManagerConfiguration` never supplies it.
12
13## Goals / Non-Goals
14
15**Goals:**
16- Every NixOS host from this flake boots new user sessions into GNOME dark mode without per-host or per-user opt-in.
17- The setting remains a normal, user-changeable GNOME Settings toggle.
18- GNOME Tweaks is provisioned exactly where GNOME is present, not merely wherever the package happens to build (i.e. not "any Linux").
19
20**Non-Goals:**
21- Locking or enforcing dark mode (`lockAll` / `locks` are intentionally not used).
22- Managing dark-mode-equivalent settings for individual apps (e.g. Firefox's own theme, GTK app-specific accent colors) — only the GNOME shell/interface-level `color-scheme` key is covered.
23- Any home-manager-level (per-user Nix) implementation — this is a NixOS system module change only, matching where `gnome-desktop`'s other requirements already live (`modules/nixos/common.nix`), and it is Linux/GNOME-specific so it does not belong in the cross-platform `modules/home/*` tree.
24
25## Decisions
26
27**Decision: implement via `programs.dconf.profiles.user.databases`, not home-manager's `dconf.settings`.**
28- Alternatives considered: home-manager exposes its own `dconf.settings` option per-user. Rejected because (a) `modules/home/*.nix` is shared across both `tom@linux` and `tom@darwin` home-manager configurations, and dconf/GNOME concepts don't apply on Darwin — it would need an `isLinux` guard for no benefit; (b) the `gnome-desktop` capability's other requirements are all expressed as NixOS system module config in `modules/nixos/common.nix`, keyed off "every NixOS host," not per-configured-home-manager-user, so the NixOS-level mechanism is the better fit and requires no per-user wiring at all — it applies to any user account on the host, including ones outside this flake's home-manager scope.
29
30**Decision: set only `org/gnome/desktop/interface color-scheme = "prefer-dark"`, no `gtk-theme`/`icon-theme` overrides.**
31- `color-scheme` is the single key GNOME Shell (and GTK4/libadwaita apps) read to decide light vs. dark; setting it is sufficient for "dark mode" as commonly understood and matches exactly what GNOME Settings' Appearance toggle itself writes. Also setting a specific dark GTK theme name was considered and rejected as unnecessary scope — GNOME's stock Adwaita theme already responds to `color-scheme` directly.
32
33**Decision: no lock, so the default only applies until the user changes it themselves.**
34- Matches the request's literal phrasing ("dark mode ... enabled by default") rather than "enforced." Also avoids surprising a user who deliberately switches to light mode having it reset.
35
36**Decision: gate GNOME Tweaks on `osConfig.services.desktopManager.gnome.enable`, not on `pkgs.stdenv.hostPlatform.isLinux`.**
37- Alternatives considered:
38 - `isLinux`, matching the existing `teams-for-linux` pattern — this was the first draft, and is wrong: `modules/home/desktop-apps.nix` is also consumed by the standalone, non-NixOS `homeConfigurations."tom@linux"`, which has no GNOME involved at all. `isLinux` would install GNOME Tweaks there regardless.
39 - Checking only `osConfig != null` (i.e. "are we integrated into any NixOS system at all") — rejected as less precise than checking the actual `gnome.enable` value: it would silently keep installing GNOME Tweaks if a future NixOS host in this flake ever disabled GNOME.
40 - Chosen: `(osConfig.services.desktopManager.gnome.enable or false)`. Requires adding `osConfig ? null` to `modules/home/desktop-apps.nix`'s function signature so the module still evaluates standalone, where `osConfig` is never supplied.
41- Effect: `teams-for-linux` keeps its existing `isLinux`-only gating in `linuxOnlyApps` (it works on any Linux desktop, no GNOME dependency). GNOME Tweaks is not added to that list; it gets its own `lib.optional (osConfig.services.desktopManager.gnome.enable or false) pkgs.gnome-tweaks`, combined into the same filtered package list.
42
43## Risks / Trade-offs
44
45- [A user who already has an existing dconf database with no explicit `color-scheme` value keeps seeing whatever GNOME's own compiled-in default was before this change (light) until dark mode is written by the new default db] → Not applicable in practice: the new default database is searched immediately after the user db on every session; since the user never wrote `color-scheme` explicitly, the fallback applies from the next login onward with no migration step needed.
46- [`programs.dconf.enable` might not be implied for every code path that sets `services.desktopManager.gnome.enable`] → Mitigate by explicitly setting `programs.dconf.enable = true;` alongside the new `profiles.user.databases` entry in `modules/nixos/common.nix`, rather than relying on it being pulled in transitively.
47- [`osConfig` could in principle be absent for a reason other than "standalone, no GNOME" in some future home-manager version] → Mitigated by using `osConfig ? null` with an explicit `or false` fallback rather than assuming absence means anything specific: the check degrades safely to "excluded" whether `osConfig` is missing entirely or present with GNOME disabled.
48
49## Migration Plan
50
51Purely additive NixOS module config; takes effect on next `nixos-rebuild switch` and next user login (dconf reads happen at session start, not via hot-reload of the system config). No rollback concerns beyond reverting the module change — no data migration, no locked state to undo.
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/proposal.md b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/proposal.md
new file mode 100644
index 0000000..44969e4
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/proposal.md
@@ -0,0 +1,30 @@
1## Why
2
3Tom wants Ghostty as an available terminal emulator (with its config stowed from the personal dotfiles repo, same as any other dotfiles package), GNOME Tweaks available for customizing desktop settings, and GNOME to boot into dark mode by default instead of the current light default.
4
5## What Changes
6
7- Add `pkgs.ghostty` to `modules/home/desktop-apps.nix`'s cross-platform app list, following the existing `lib.meta.availableOn` filtering pattern. Verified against the flake's pinned `nixos-unstable` nixpkgs: `ghostty` is MIT-licensed and currently builds only on Linux platforms there (no `darwin` entries in `meta.platforms` yet) — the existing availableOn filter already excludes it on `tom@darwin` without any code change, per the desktop-applications capability's existing "unsupported packages are skipped" requirement.
8- No dotfiles-module change for stowing Ghostty's config: `modules/home/dotfiles.nix` already stows every top-level package directory in the cloned dotfiles repo except platform-default or explicitly excluded ones, and `ghostty` is not in either exclude list — so once a `ghostty/` package directory exists in the dotfiles repo, it is symlinked automatically by the existing behavior. Nothing to change here; noted for clarity since the request called it out explicitly.
9- Add `pkgs.gnome-tweaks` to `modules/home/desktop-apps.nix`, gated on GNOME actually being enabled rather than merely on Linux: `lib.optional (osConfig.services.desktopManager.gnome.enable or false) pkgs.gnome-tweaks`, requiring `osConfig ? null` to be added to the module's function signature (see design.md). `modules/home/desktop-apps.nix` is shared by both every NixOS host (where GNOME is force-enabled) and the standalone, non-NixOS `homeConfigurations."tom@linux"` — a plain `isLinux` gate (the `teams-for-linux` pattern) would wrongly install GNOME Tweaks on the latter, which has no GNOME. Verified GPL-3.0-or-later license — no unfree-allowlist change needed.
10- Add a system-wide GNOME dark-mode default to `modules/nixos/common.nix`, alongside the existing `services.desktopManager.gnome.enable = true;`, via NixOS's dconf default-database mechanism (`org/gnome/desktop/interface color-scheme = "prefer-dark"`). This sets the *default* only — it does not lock the setting, so a user can still switch back to light mode from GNOME Settings. Design in `design.md` covers the exact NixOS option used.
11- **BREAKING**: none — additive only. Existing users who already manually switched to dark or light mode are unaffected by a default (dconf defaults only apply where no user value is already set).
12
13## Capabilities
14
15### New Capabilities
16(none)
17
18### Modified Capabilities
19- `desktop-applications`: add a requirement that Ghostty is provisioned via the shared home profile like Firefox/Bitwarden (cross-platform, filtered by package availability), plus a separate requirement that GNOME Tweaks is provisioned only where GNOME is enabled (NixOS hosts), not merely wherever the package builds (any Linux).
20- `gnome-desktop`: add a requirement that every NixOS host built from this flake's shared system module defaults its GNOME session to dark mode, while leaving the setting user-changeable.
21
22(`dotfiles-management` is unaffected at the requirement level: Ghostty's dotfiles package is stowed automatically under the existing "non-excluded package is still stowed" requirement — no new or changed requirement needed.)
23
24## Impact
25
26- **Affected code**: `modules/home/desktop-apps.nix` (add `ghostty` to `crossPlatformApps`; add `osConfig ? null` to the module's arguments and a new `osConfig`-gated `gnome-tweaks` entry, kept separate from `linuxOnlyApps`), `modules/nixos/common.nix` (add dconf default-database config for dark mode).
27- **Not affected**: `lib/unfree-allowlist.nix` (both new packages are free-licensed), `modules/home/dotfiles.nix` (Ghostty's dotfiles package needs no exclude-list or code change to be stowed).
28- **Dependencies**: nixpkgs' `ghostty` and `gnome-tweaks` packages (already present in the pinned `nixos-unstable` input; no new flake inputs). The personal dotfiles repo (`https://git.tomvanderlee.com/dotfiles`, cloned via `home.dotfiles.repoUrl` in `users/tom.nix`) is expected to already contain, or will need, a top-level `ghostty/` package directory for its config to actually be stowed — that repo lives outside this flake and is out of scope for this change to edit.
29- **Platforms**: Ghostty is Linux-only in nixpkgs today, so it doesn't appear on `tom@darwin`. GNOME Tweaks is gated on GNOME being enabled rather than on platform: it appears in a NixOS host's home-manager activation (e.g. `nixosConfigurations.test-vm`'s `home-manager.users.tom`) but not in the standalone `homeConfigurations."tom@linux"` or `"tom@darwin"`, even though `tom@linux` is technically Linux. The dark-mode default likewise only applies to NixOS hosts.
30- **Known limitation, out of scope**: this change does not modify the external dotfiles repository itself (creating a `ghostty/` package there is a separate, out-of-flake step); it also does not lock the dark-mode dconf key, so it is a default rather than an enforced policy, per the request wording ("enabled by default").
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/desktop-applications/spec.md b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/desktop-applications/spec.md
new file mode 100644
index 0000000..ccc88e4
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/desktop-applications/spec.md
@@ -0,0 +1,21 @@
1## MODIFIED Requirements
2
3### Requirement: Desktop GUI applications are provisioned via the shared home profile
4The shared home-manager profile SHALL include Slack, Discord, Spotify, teams-for-linux, Firefox, the Bitwarden desktop client, and Ghostty as GUI application packages, available wherever that profile is activated and the underlying package supports the current system. GNOME Tweaks is provisioned per the separate requirement below, since its availability depends on GNOME being enabled rather than on platform support alone.
5
6#### Scenario: GUI app available after activation
7- **WHEN** the shared home profile is activated on a system for which a given desktop application's package is supported
8- **THEN** that application is available without any additional manual installation step
9
10## ADDED Requirements
11
12### Requirement: GNOME Tweaks is provisioned only where GNOME is enabled
13GNOME Tweaks SHALL be included in the provisioned package set only where the GNOME desktop is enabled (every NixOS host built from this flake's shared system module), and SHALL be excluded wherever GNOME is not known to be enabled, including standalone (non-NixOS) home-manager activations of the shared profile.
14
15#### Scenario: Included on a NixOS host with GNOME enabled
16- **WHEN** the shared home profile is activated as part of a NixOS host built from this flake's shared system module, where GNOME is enabled
17- **THEN** GNOME Tweaks is included in the provisioned package set
18
19#### Scenario: Excluded on a standalone activation
20- **WHEN** the shared home profile is activated standalone, not as part of a NixOS system (for example via `home-manager switch` on a non-NixOS machine)
21- **THEN** GNOME Tweaks is not included in the provisioned package set, regardless of the host's operating system
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/gnome-desktop/spec.md b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/gnome-desktop/spec.md
new file mode 100644
index 0000000..f9344b4
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/specs/gnome-desktop/spec.md
@@ -0,0 +1,12 @@
1## ADDED Requirements
2
3### Requirement: GNOME defaults to dark mode
4Every NixOS host built from this flake's shared system module SHALL configure its GNOME desktop session to use dark mode (`color-scheme: prefer-dark`) as the default appearance, while leaving the setting changeable by the user.
5
6#### Scenario: Fresh session uses dark mode
7- **WHEN** a user who has not previously changed the GNOME appearance setting logs into a NixOS host built from this flake's shared system module
8- **THEN** the GNOME desktop session appears in dark mode
9
10#### Scenario: User can still switch to light mode
11- **WHEN** a user opens GNOME Settings' Appearance page on a host built from this flake's shared system module
12- **THEN** the user can select light mode, and that choice takes effect and persists across future logins
diff --git a/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/tasks.md b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/tasks.md
new file mode 100644
index 0000000..15eca5b
--- /dev/null
+++ b/openspec/changes/add-ghostty-gnome-tweaks-dark-mode/tasks.md
@@ -0,0 +1,15 @@
1## 1. Ghostty and GNOME Tweaks packages
2
3- [x] 1.1 Add `pkgs.ghostty` to `crossPlatformApps` in `modules/home/desktop-apps.nix` and verify `nix eval '.#homeConfigurations."tom@linux".config.home.packages'` includes it while `nix eval '.#homeConfigurations."tom@darwin".config.home.packages'` does not (nixpkgs currently has no Darwin build).
4- [x] 1.2 Add `osConfig ? null` to `modules/home/desktop-apps.nix`'s function arguments, and add `pkgs.gnome-tweaks` via `lib.optional (osConfig.services.desktopManager.gnome.enable or false) pkgs.gnome-tweaks` (kept separate from `linuxOnlyApps`, which stays `teams-for-linux`-only). Verify `nix eval '.#homeConfigurations."tom@linux".config.home.packages'` excludes `gnome-tweaks` (standalone, no `osConfig`), while `nix eval '.#nixosConfigurations.test-vm.config.home-manager.users.tom.home.packages'` includes it (NixOS host, GNOME enabled).
5- [x] 1.3 Build both home configurations end to end (`nix build '.#homeConfigurations."tom@linux".activationPackage'` and `.../"tom@darwin".activationPackage`) and verify both evaluate and build successfully with no unfree-allowlist errors.
6
7## 2. GNOME dark-mode default
8
9- [x] 2.1 Add `programs.dconf.enable = true;` and `programs.dconf.profiles.user.databases = [ { settings."org/gnome/desktop/interface".color-scheme = "prefer-dark"; } ];` to `modules/nixos/common.nix`, alongside the existing `services.desktopManager.gnome.enable = true;`.
10- [x] 2.2 Build a NixOS host from this flake (`nix build '.#nixosConfigurations.<hostname>.config.system.build.toplevel'` for an existing host, e.g. `test-vm`) and verify the build succeeds.
11- [x] 2.3 On a booted host (or a VM built from it), verify a fresh user session (no prior `color-scheme` set in that user's own dconf database) starts in dark mode, and that switching to light mode from GNOME Settings' Appearance page still works and persists across a re-login.
12
13## 3. Spec sync
14
15- [x] 3.1 Verify `openspec validate --change add-ghostty-gnome-tweaks-dark-mode --strict` passes once the above are implemented, confirming the delta specs match the shipped behavior.