Compare commits

...

10 commits

Author SHA1 Message Date
randogoth
eb9d7fb9b8 gnome: fix two extensions broken by the GNOME 49 -> 50 bump
Tracking nixos-26.05 moved GNOME Shell from 49 to 50, and the shell
hard-disables any extension whose metadata.json shell-version array
lacks the running major. Two enabled extensions were left OUT OF DATE,
for different reasons:

- logomenu@aryan_k was pinned to the v38 zip only because the
  custom-menu patch was written against v38. nixpkgs 26.05 already
  ships v41, which supports shell 50, and the patch applies to it
  cleanly. Drop the version/src pin and keep the override patch-only.

- all-in-one-clipboard is still packaged as v19 (shell <=49) on the
  nixos-26.05 branch; the shell-50 build (v30) landed in unstable and
  was never backported. Pin src to the v30 zip until it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ABzc7ivGbjKRCASa8uEkjd
2026-08-31 20:20:04 +03:00
randogoth
9f28569fef shell-init: record the first command of every shell in atuin
bash-preexec arms its DEBUG trap from __bp_interactive_mode at the end of
PROMPT_COMMAND, but its lazy installer runs mid-way through the first prompt
because zoxide and ghostty append their hooks after it. Those hooks disarm the
trap again, so the first interactive command of every session never reached
preexec and atuin silently dropped it.

Arm from PS0 instead, which is expanded once per interactive command before the
DEBUG trap and is therefore independent of PROMPT_COMMAND ordering.

Also guard the script against running twice: it is installed as both
loginShellInit and interactiveShellInit, and /etc/profile sources /etc/bashrc,
which registered starship's precmd/preexec hooks twice in every login shell.
2026-08-28 16:06:09 +03:00
randogoth
3f29ad6cec remove lowercase agents.md (superseded by AGENTS.md)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:48:25 +03:00
randogoth
228fe626b5 gitignore: ignore .claude/ (local assistant config)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:48:25 +03:00
randogoth
d1321cf7ca docs: nixos-26.05 in adopt examples, document impermanence
Bump the wrapper-flake nixpkgs channel in the adopt/laptop examples to
nixos-26.05, and add the "Impermanence (optional)" section covering the
/persist subvolume, the required "nixos" fs label, and the default
persistence set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:38:06 +03:00
randogoth
17cce973fc impermanence: port btrfs rollback to systemd-stage-1 initrd
nixos-26.05 asserts against boot.initrd.postDeviceCommands under the
systemd stage-1 initrd. Move the root-subvolume rollback into an initrd
systemd oneshot (ordered after the labelled device, before sysroot.mount).
Same rollback logic; awk swapped for cut since coreutils' cut is in the
systemd initrd but awk is not.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:14:53 +03:00
randogoth
72941092d2 26.05: source Lix from nixpkgs, fix disko btrfs label
nixos-26.05 removed lix_2_93, which the lix-module release-2.93 branch
hard-pins via lixFromNixpkgs (no 2.94 module release exists yet). Drop
the lix-module input and set nix.package = pkgs.lix, which is Lix 2.94.2
on 26.05 — so we stay on Lix, just sourced from nixpkgs.

Also: newer disko dropped the btrfs `label` option; pass -L nixos via
extraArgs instead so the impermanence rollback still finds the "nixos"
label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:11:17 +03:00
randogoth
2f9293f698 flake: track nixos-26.05 (nixos-25.11 is EOL)
nixos-25.11 reached end-of-life (frozen upstream at b6018f8), so
`nix flake update` no longer pulls system package updates. Move the
default nixpkgs channel to the current stable release, nixos-26.05.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 12:04:46 +03:00
randogoth
86b5c2422e just: parameterize update recipe (system/home/both)
`just update system` re-locks + rebuilds the NixOS system flake,
`just update home` re-locks + switches the Home Manager flake, and
`just update` with no arg does both (system first). Previously update
only touched the system flake, leaving the Home Manager side stale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-28 11:23:26 +03:00
randogoth
be7ecfc0ea desktop: replace Thunar with Nautilus, add File Roller
Thunar didn't integrate cleanly with the GNOME session. Drop the
XFCE file-manager module (thunar/xfconf/exo/tumbler) and restore
Nautilus as the native file manager: un-exclude nautilus, point the
dash favorite at org.gnome.Nautilus.desktop, remove the Thunar
desktop override, and keep gvfs (moved into gnome.nix) for mounting,
trash, and network shares. Add file-roller for archive-manager
integration in Nautilus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:15:20 +02:00
14 changed files with 360 additions and 506 deletions

3
.gitignore vendored
View file

@ -4,3 +4,6 @@ result
.DS_Store
hosts/*-hardware.nix
hosts/local-*.nix
# editor / assistant local config
.claude/

310
agents.md
View file

@ -1,310 +0,0 @@
# agents.md — NixOS (Lix) Configuration Agent
## Role
You are an expert **NixOS configuration agent** specializing in:
- **Flake-first NixOS**
- **Lix-flavored Nix (preferred but not mandatory)**
- **Modular NixOS + Home Manager systems**
- **Flake-contained host modules (“configuration.nix-style”)**
- Deterministic, reproducible configurations
You assist by **editing or proposing Nix code**.
You do **not** explain Nix concepts unless explicitly requested.
---
## Authority Model
1. **`flake.nix` is the sole entry point**
- All evaluation flows through `outputs`
- No channel-based workflows
- No implicit `NIX_PATH`
- No reliance on `/etc/nixos`
2. **All systems are flakes**
- Legacy `configuration.nix` as an entry point is forbidden
- Files that *look* like `configuration.nix` are allowed **only as flake-contained host modules**
---
## Required Workflow
### Before Making Any Changes
You **must present a concise plan** and wait for confirmation.
The plan must include:
- Bullet points only
- Exact file paths to be touched
- High-level intent per file
- No code
- No prose explanations
Example:
```text
Plan:
- Add flake.nix with pinned nixpkgs
- Add hosts/laptop.nix as host module
- Add modules/system/base.nix
- Wire host via nixosConfigurations
````
You may **only modify files listed in the approved plan**.
Scope is **strict**.
### Permission Gates (New Directive)
You must ask for explicit confirmation before doing any of the following:
- Running tests/builds/evaluations (e.g. `nix build`, `nix flake check`, `nixos-rebuild`, `home-manager switch`)
- Creating commits (`git commit`, `git revert`, etc.)
- Pushing to any remote (`git push`, etc.)
If you already presented a plan, you must still ask again before crossing one of
these gates.
---
## Flake-Contained `configuration.nix`-Style Modules (Host Modules)
### Definition
A **host module** is a NixOS module that:
* Has the standard module signature:
```nix
{ config, pkgs, ... }:
```
* Looks like a traditional `configuration.nix`
* Is **not** an entry point
* Is **only evaluated via `flake.nix`**
* Exists solely to **compose a specific machine**
This pattern is **explicitly allowed and encouraged** when used correctly.
---
### Allowed Responsibilities (Host Modules)
Host modules **may**:
* Compose the system via `imports`
* Set host-specific values:
* `networking.hostName`
* `system.stateVersion`
* locale / timezone
* Apply small, truly host-unique overrides
Example:
```nix
# hosts/laptop.nix
{ config, pkgs, ... }:
{
imports = [
../modules/system/base.nix
../modules/desktop/wayland.nix
../modules/users/tlalit.nix
];
networking.hostName = "laptop";
system.stateVersion = "24.11";
}
```
---
### Forbidden Responsibilities (Host Modules)
Host modules **must not**:
* Implement reusable features
* Contain large logic blocks
* Define users inline
* Enable services that could apply to more than one host
* Act as monolithic system definitions
Rule of thumb (enforced):
> **Host modules compose. Feature modules implement.**
If a setting could plausibly apply to more than one host, it does **not** belong in a host module.
---
## Module Categories
### Host Modules
* Path: `hosts/*.nix`
* Role: composition only
* Small, declarative
* No reusable logic
### Feature Modules
* Path: `modules/**`
* Role: implementation
* Reusable
* Use upstream NixOS options only
* **No custom option namespaces**
Example feature module skeleton:
```nix
{ config, lib, pkgs, ... }:
{
config = {
# implementation using upstream options
};
}
```
---
## Home Manager Policy
* Home Manager is **provided as a CLI tool system-wide** (`home-manager` in `environment.systemPackages`).
* Users manage their own HM configs (per-user, standalone). No system-wide HM module imports.
* `modules/users/*` must not declare `home-manager.users.*`; keep user accounts declarative via NixOS only.
---
## Hardware Policy
* GPU support and Btrfs support are desired
* Hardware modules are allowed
* **Hardware changes must be explicitly included in the plan**
* No surprise disk, bootloader, or kernel changes
---
## Overlays Policy
* Overlays are **allowed but discouraged**
* The agent **must not introduce overlays unless explicitly requested**
* Prefer:
* explicit flake inputs
* local `callPackage`
* direct package references
No proactive overlay usage.
---
## Code Style Rules
### Nix
* Pure Nix only
* Prefer explicit attribute paths
* Prefer:
* `lib.mkIf`
* `lib.mkMerge`
* `lib.optionals`
* Avoid:
* `with pkgs;`
* implicit imports
* inline shell hacks
### Formatting
* All Nix code must conform to **`nixfmt-rfc-style`**
* Do not reformat unrelated files
---
## Scripting Policy
1. **Prefer Python 3**
* Scripts must be deterministic and non-interactive
* Stored under `./scripts/`
* May run **at activation time only**
* Not at evaluation time
* Not at build time unless explicitly requested
2. **Shell scripts**
* Allowed only when unavoidable
* POSIX-compliant
* Minimal
* Generated via `writeShellScriptBin` if needed
3. **Never embed large scripts inline**
---
## Expected Repository Layout
```text
.
├── flake.nix
├── flake.lock
├── hosts/
│ └── hostname.nix
├── modules/
│ ├── system/
│ ├── hardware/
│ ├── services/
│ ├── desktop/
│ ├── users/
│ └── development/
├── scripts/
└── lib/
```
* `flake.nix` → authority
* `hosts/` → composition
* `modules/` → behavior
---
## Safety & Reproducibility
* No imperative installs
* No network access at evaluation
* Inputs must be pinned
* All changes must be declarative
---
## Output Rules
* Plans: **plan only**
* Code: **code only**
* Questions: **one precise question only**
```
---
If you want, next we can:
- Add **machine-checkable lint rules** derived from this
- Write a **migration appendix** for legacy `/etc/nixos`
- Create a **Codex system prompt** that mirrors this file exactly
```
---
## Test VM (current)
- Built from our installer ISO (`nixos-minimal-25.11.20260130.63590ac-x86_64-linux.iso`).
- Hostname: `nanuqsaurus`.
- User: `admin` / password `admin`.
- Network: DHCP on primary interface (e.g., `ensp1s0` in VM); SSH reachable once IP obtained.
- Purpose: sandbox for validating flake changes before baking into the ISO.
- Workflow: sync repo to VM and `nixos-rebuild switch --flake /etc/nixos#installer`; rebuild ISO **only on explicit request** (ISO must remain hardware-agnostic, no embedded host-specific files).
- Host-local files: the installer writes `hosts/local-<hostname>.nix` and `hosts/local-<hostname>-hardware.nix` on the target. These are ignored by git. When syncing, exclude them to avoid deletion:
`rsync -a --exclude 'hosts/local-*.nix' --exclude 'hosts/*-hardware.nix' --exclude '.git' . admin@<vm>:/home/admin/nixos-sync`

View file

@ -22,7 +22,7 @@ On the target machine:
description = "Local wrapper for the nanuqsaurus profile";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
nanuqsaurus = {
url = "git+https://codeberg.org/randogoth/nanuqsaurus.git";
inputs.nixpkgs.follows = "nixpkgs";
@ -53,6 +53,8 @@ On the target machine:
{
# Optional: change the default admin username ("admin")
nanuqsaurus.admin.username = "admin";
# Optional: enable impermanence (requires a /persist Btrfs subvolume and mounts in hardware-configuration.nix)
# nanuqsaurus.impermanence.enable = true;
networking.hostName = "nanuqsaurus";
system.stateVersion = "25.11";
}
@ -75,3 +77,28 @@ sudo nixos-rebuild switch --flake /etc/nixos#nanuqsaurus
- `sudo nixos-rebuild switch --flake /etc/nixos#nanuqsaurus`
- Keep all your machine-specific changes in the wrapper flake (additional modules, packages, services, etc.).
## Impermanence (optional)
If you enable `nanuqsaurus.impermanence.enable = true;` you must:
- Add a `/persist` mount (Btrfs subvolume) in `hardware-configuration.nix`.
- Migrate state you care about into `/persist` before the first reboot.
Notes:
- The rollback logic expects the root Btrfs volume label to be `nixos`.
- Create the subvolume with `btrfs subvolume create /mnt/persist` and mount it as `/persist`.
The default persistence set includes:
- `/etc/nixos`
- `/etc/ssh`
- `/etc/cups`
- `/var/lib/cups`
- `/var/lib/libvirt`
- `/var/lib/secureboot`
- `/var/lib/tailscale`
- `/var/lib/systemd`
- `/var/lib/nixos`
- `/etc/machine-id`

95
flake.lock generated
View file

@ -125,39 +125,6 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flakey-profile": {
"locked": {
"lastModified": 1712898590,
"narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=",
"owner": "lf-",
"repo": "flakey-profile",
"rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d",
"type": "github"
},
"original": {
"owner": "lf-",
"repo": "flakey-profile",
"type": "github"
}
},
"flox": {
"inputs": {
"crane": "crane",
@ -288,44 +255,6 @@
"type": "github"
}
},
"lix": {
"flake": false,
"locked": {
"lastModified": 1768477252,
"narHash": "sha256-RgET5pILoiG+3GnDpgfUEA4y8ISfZe6SB+geE+8U76Y=",
"rev": "fbe811e94e9c4efc9b9c283fe2fbb3aeff50fca7",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/fbe811e94e9c4efc9b9c283fe2fbb3aeff50fca7.tar.gz?rev=fbe811e94e9c4efc9b9c283fe2fbb3aeff50fca7"
},
"original": {
"type": "tarball",
"url": "https://git.lix.systems/lix-project/lix/archive/release-2.93.tar.gz"
}
},
"lix-module": {
"inputs": {
"flake-utils": "flake-utils",
"flakey-profile": "flakey-profile",
"lix": "lix",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1756125859,
"narHash": "sha256-6a+PWILmqHCs9B5eIBLg6HSZ8jYweZpgOWO8FlyVwYI=",
"ref": "release-2.93",
"rev": "d3292125035b04df00d01549a26e948631fabe1e",
"revCount": 156,
"type": "git",
"url": "https://git.lix.systems/lix-project/nixos-module"
},
"original": {
"ref": "release-2.93",
"type": "git",
"url": "https://git.lix.systems/lix-project/nixos-module"
}
},
"nix-flatpak": {
"locked": {
"lastModified": 1767983141,
@ -380,16 +309,16 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1769741972,
"narHash": "sha256-RxSg1EioTWNpoLaykiT1UQKTo/K0PPdLqCyQgNjNqWs=",
"lastModified": 1787753485,
"narHash": "sha256-BZWCi9ZRJiARTuKTbbtvFTj7t1TK4G3UEckT3HyNfRg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "63590ac958a8af30ebd52c7a0309d8c52a94dd77",
"rev": "062346a6d85bc4b49dfaa61c986e9c5be21217d1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.11",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
@ -467,7 +396,6 @@
"flox": "flox",
"impermanence": "impermanence",
"lanzaboote": "lanzaboote",
"lix-module": "lix-module",
"nix-flatpak": "nix-flatpak",
"nix-index-database": "nix-index-database",
"nixpkgs": "nixpkgs_2",
@ -511,21 +439,6 @@
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View file

@ -2,7 +2,7 @@
description = "NixOS installation ISO with Lix";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
@ -20,8 +20,6 @@
url = "github:nix-community/NUR";
inputs.nixpkgs.follows = "nixpkgs";
};
lix-module.url = "git+https://git.lix.systems/lix-project/nixos-module?ref=release-2.93";
lix-module.inputs.nixpkgs.follows = "nixpkgs";
lanzaboote.url = "github:nix-community/lanzaboote";
lanzaboote.inputs.nixpkgs.follows = "nixpkgs";
flox.url = "github:flox/flox";

208
laptop.md Normal file
View file

@ -0,0 +1,208 @@
# Install Nanuqsaurus On An Empty Partition (No Full-Disk Wipe)
This repos `nanuqsaurus-btrfs` “fresh install” path uses `disko` to create a brand new GPT layout (EFI + Btrfs) and therefore **wipes the whole disk**. If you want to install onto an **existing empty partition** while keeping other partitions intact, use the “wrapper flake” approach and a manual mount + `nixos-install`.
These steps are meant to be run from a **NixOS installer ISO** on the target laptop.
## 0) Preconditions
- Boot the installer in **UEFI mode** (this profile enables `systemd-boot` + EFI).
- You have working network connectivity (WiFi instructions below).
- You have:
- an existing **empty root partition** you will format (example: `/dev/nvme0n1p6`)
- an existing **EFI System Partition** (vfat) you will mount at `/boot` (example: `/dev/nvme0n1p1`)
Confirm UEFI:
```bash
test -d /sys/firmware/efi/efivars && echo "UEFI booted" || echo "NOT UEFI booted"
```
## 0.5) Connect To WiFi (Installer)
Most NixOS installer ISOs run NetworkManager. The easiest flow is `nmtui`.
1) Bring up the text UI and connect:
```bash
sudo -i
nmtui
```
In `nmtui`:
- Select `Activate a connection`
- Pick your WiFi SSID
- Enter the password
- Exit
2) Verify you have connectivity:
```bash
ping -c 1 1.1.1.1
ping -c 1 example.com
```
If `nmtui` is unavailable, try:
```bash
nmcli dev status
nmcli dev wifi list
nmcli dev wifi connect "YOUR_SSID" password "YOUR_PASSWORD"
```
## 1) Identify Your Partitions
```bash
lsblk -f
```
Pick stable paths if available (`/dev/disk/by-id/...`). In the commands below, set:
- `ROOT_PART` = the empty partition to become `/`
- `EFI_PART` = the EFI System Partition (vfat) to become `/boot`
Example:
```bash
ROOT_PART=/dev/nvme0n1p6
EFI_PART=/dev/nvme0n1p1
```
## 2) Format The Root Partition
Warning: this destroys data on `ROOT_PART`.
Recommended (Btrfs with subvolumes similar to this repos intended layout):
```bash
mkfs.btrfs -f -L nixos "$ROOT_PART"
mount "$ROOT_PART" /mnt
btrfs subvolume create /mnt/root
btrfs subvolume create /mnt/home
btrfs subvolume create /mnt/nix
umount /mnt
mount -o subvol=root,compress=zstd "$ROOT_PART" /mnt
mkdir -p /mnt/home /mnt/nix
mount -o subvol=home,compress=zstd "$ROOT_PART" /mnt/home
mount -o subvol=nix,compress=zstd "$ROOT_PART" /mnt/nix
```
Alternative (ext4):
```bash
mkfs.ext4 -F -L nixos "$ROOT_PART"
mount "$ROOT_PART" /mnt
mkdir -p /mnt/nix
```
## 3) Mount EFI At `/boot`
```bash
mkdir -p /mnt/boot
mount "$EFI_PART" /mnt/boot
```
## 4) Generate Hardware Config
Important: do this **after** mounting `/boot`, so the EFI mount gets captured.
```bash
nixos-generate-config --root /mnt
```
This creates:
- `/mnt/etc/nixos/hardware-configuration.nix`
- `/mnt/etc/nixos/configuration.nix` (we will not use this directly)
## 5) Create A Wrapper Flake In `/etc/nixos`
This repos `nanuqsaurus` profile defines an `admin` user and also tends to lock `root` by default. To avoid surprises, set your own password hashes in the wrapper flake using `lib.mkForce`.
If you have a Lenovo ThinkPad X13 (Intel), you can also import the `nixos-hardware` module for it in this wrapper flake.
1) Generate SHA-512 password hashes:
```bash
nix --experimental-features "nix-command flakes" \
shell nixpkgs#mkpasswd -c mkpasswd -- -m sha-512
```
Run it twice if you want to set both `admin` and `root`.
2) Create `/mnt/etc/nixos/flake.nix`:
```bash
nano /mnt/etc/nixos/flake.nix
```
Paste and edit:
```nix
{
description = "Local wrapper for the nanuqsaurus profile";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
nanuqsaurus = {
url = "git+https://codeberg.org/randogoth/nanuqsaurus.git";
inputs.nixpkgs.follows = "nixpkgs";
};
# Optional hardware profiles (recommended on laptops)
nixos-hardware = {
url = "github:NixOS/nixos-hardware";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ nixpkgs, nanuqsaurus, nixos-hardware, ... }: {
nixosConfigurations.nanuqsaurus = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; };
modules = [
./hardware-configuration.nix
# Optional: ThinkPad X13 (Intel) profile (path: lenovo/thinkpad/x13/intel)
# Remove or replace if you have different hardware.
nixos-hardware.nixosModules.lenovo-thinkpad-x13-intel
nanuqsaurus.nixosModules.nanuqsaurus
({ lib, ... }: {
networking.hostName = "nanuqsaurus";
system.stateVersion = "25.11";
nanuqsaurus.admin.username = "admin";
users.users.admin.hashedPassword = lib.mkForce "PUT_ADMIN_SHA512_HASH_HERE";
# Recommended so you can recover easily:
users.users.root.hashedPassword = lib.mkForce "PUT_ROOT_SHA512_HASH_HERE";
# Optional: require sudo password (this repo defaults to passwordless sudo)
security.sudo.wheelNeedsPassword = lib.mkForce true;
})
];
};
};
}
```
## 6) Install NixOS
```bash
NIX_CONFIG="experimental-features = nix-command flakes" \
nixos-install --root /mnt --flake /mnt/etc/nixos#nanuqsaurus
```
## 7) Reboot
```bash
reboot
```
If your firmware shows multiple boot options, select the systemd-boot entry for the disk containing the EFI partition.
## Notes
- Secure Boot: this repos installer ISO expects Secure Boot off at boot; after installation you can enable Secure Boot using Lanzaboote (see `docs/secure-boot.md`).
- If you actually want to wipe an entire disk and let this repo handle partitioning, use `disko-install` with `#nanuqsaurus-btrfs` (see `README.md` and `docs/install-help.txt`).

View file

@ -1,30 +1,6 @@
{ lib, pkgs, ... }:
let
thunarDesktopOverride = pkgs.makeDesktopItem {
name = "thunar";
desktopName = "Files";
genericName = "File Manager";
tryExec = "thunar";
exec = "thunar %U";
icon = "org.xfce.thunar";
categories = [
"Utility"
"FileManager"
];
mimeTypes = [ "inode/directory" ];
keywords = [
"folder"
"manager"
"explorer"
"files"
];
startupNotify = true;
startupWMClass = "Thunar";
terminal = false;
comment = "Browse files";
};
ptyxisDesktopOverride = pkgs.makeDesktopItem {
name = "org.gnome.Ptyxis";
desktopName = "Terminal";
@ -41,7 +17,6 @@ let
in
{
environment.systemPackages = lib.mkAfter [
(lib.hiPrio thunarDesktopOverride)
(lib.hiPrio ptyxisDesktopOverride)
];
}

View file

@ -1,27 +0,0 @@
{ pkgs, ... }:
{
environment.etc."xdg/xfce4/xfconf/xfce-perchannel-xml/exo.xml".text = ''
<?xml version="1.0" encoding="UTF-8"?>
<channel name="exo" version="1.0">
<property name="helpers" type="empty">
<property name="TerminalEmulator" type="string" value="${pkgs.ptyxis}/bin/ptyxis"/>
</property>
</channel>
'';
services.gvfs.enable = true;
services.tumbler.enable = true;
programs.thunar = {
enable = true;
plugins = [
pkgs.xfce.thunar-archive-plugin
pkgs.xfce.thunar-media-tags-plugin
pkgs.xfce.thunar-vcs-plugin
pkgs.xfce.thunar-volman
];
};
programs.xfconf.enable = true;
}

View file

@ -2,13 +2,18 @@
let
logoMenuExtension = pkgs.gnomeExtensions.logo-menu.overrideAttrs (old: {
version = "38";
patches = (old.patches or [ ]) ++ [ ./patches/logo-menu-custom-menu.patch ];
});
# nixos-26.05 still packages v19, which caps out at GNOME Shell 49; the
# shell-50 build landed only in nixpkgs unstable. Drop once 26.05 backports it.
aioClipboardExtension = pkgs.gnomeExtensions.all-in-one-clipboard.overrideAttrs (_: {
version = "30";
src = pkgs.fetchzip {
url = "https://extensions.gnome.org/extension-data/logomenuaryan_k.v38.shell-extension.zip";
hash = "sha256-GdGn7YKfOOEM0kV1Gd9H5c1KKjs/+/4XCsxO2pFdqu4=";
url = "https://extensions.gnome.org/extension-data/all-in-one-clipboardNiffirgkcaJ.github.com.v30.shell-extension.zip";
hash = "sha256-zESXhXVWVttjAN/75zNfF7u7uJKGMARpilBgYkkpMWs=";
stripRoot = false;
};
patches = (old.patches or [ ]) ++ [ ./patches/logo-menu-custom-menu.patch ];
});
in
{
@ -30,6 +35,9 @@ in
services.displayManager.gdm.enable = true;
services.desktopManager.gnome.enable = true;
# Virtual filesystem backend for Nautilus: mounting, trash, network shares.
services.gvfs.enable = true;
services.gnome.core-developer-tools.enable = false;
services.gnome.games.enable = false;
@ -41,7 +49,7 @@ in
"org/gnome/shell" = {
disable-user-extensions = false;
favorite-apps = [
"thunar.desktop"
"org.gnome.Nautilus.desktop"
"org.gnome.Ptyxis.desktop"
"com.ranfdev.DistroShelf.desktop"
"io.github.kolunmi.Bazaar.desktop"
@ -94,7 +102,9 @@ in
pkgs.gnome-extension-manager
pkgs.mission-center
pkgs.papirus-icon-theme
pkgs.gnomeExtensions.all-in-one-clipboard
pkgs.file-roller
pkgs.unrar
aioClipboardExtension
pkgs.gnomeExtensions.alphabetical-app-grid
pkgs.gnomeExtensions.app-hider
pkgs.gnomeExtensions.apps
@ -129,7 +139,6 @@ in
pkgs.gnome-system-monitor
pkgs.gnome-weather
pkgs.loupe
pkgs.nautilus
pkgs.papers
# gnome-connections
pkgs.showtime

View file

@ -1,8 +1,11 @@
{ inputs }:
{ ... }:
{ pkgs, ... }:
{
# Use Lix from nixpkgs (2.94.x on nixos-26.05). The lix-module's
# lixFromNixpkgs still pins lix_2_93, which nixos-26.05 removed.
nix.package = pkgs.lix;
imports = [
inputs.lix-module.nixosModules.lixFromNixpkgs
inputs.nix-index-database.nixosModules.nix-index
inputs.nix-flatpak.nixosModules.nix-flatpak
inputs.impermanence.nixosModules.impermanence
@ -16,7 +19,6 @@
../system/printer.nix
../system/impermanence.nix
../desktop/desktop-entries.nix
../desktop/file-manager.nix
../desktop/gnome.nix
../users/admin.nix
];

View file

@ -26,8 +26,9 @@
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
label = "nixos";
# Filesystem label "nixos" is required by the impermanence rollback
# logic. Newer disko dropped the `label` option; pass it to mkfs.btrfs.
extraArgs = [ "-f" "-L" "nixos" ];
subvolumes = {
root = {
mountpoint = "/";

View file

@ -10,7 +10,20 @@
config = lib.mkIf config.nanuqsaurus.impermanence.enable {
boot.initrd.supportedFilesystems = [ "btrfs" ];
boot.initrd.postDeviceCommands = lib.mkAfter ''
# Reset the /root subvolume to a pristine snapshot on every boot.
# systemd stage-1 initrd does not support boot.initrd.postDeviceCommands, so
# this runs as an initrd systemd service, ordered after the labelled device
# appears and before the root filesystem is mounted (sysroot.mount).
# Note: `cut` (coreutils) is used instead of `awk`, which is not in the
# systemd initrd.
boot.initrd.systemd.services.rollback = {
description = "Rollback btrfs root subvolume to a pristine state";
wantedBy = [ "initrd.target" ];
after = [ "dev-disk-by\\x2dlabel-nixos.device" ];
before = [ "sysroot.mount" ];
unitConfig.DefaultDependencies = "no";
serviceConfig.Type = "oneshot";
script = ''
mkdir -p /mnt
mount -t btrfs -o subvol=/ /dev/disk/by-label/nixos /mnt
@ -25,7 +38,7 @@
btrfs subvolume snapshot /mnt/root /mnt/root-previous
while true; do
subvols="$(btrfs subvolume list -o /mnt/root | awk '{print $9}')"
subvols="$(btrfs subvolume list -o /mnt/root | cut -f9 -d' ')"
if [ -z "$subvols" ]; then
break
fi
@ -40,6 +53,7 @@
btrfs subvolume snapshot /mnt/root-blank /mnt/root
umount /mnt
'';
};
fileSystems."/persist".neededForBoot = true;

View file

@ -26,9 +26,29 @@ let
nix-collect-garbage -d
[no-cd]
update:
update target="":
#!/usr/bin/env bash
set -euo pipefail
update_system() {
sudo nix flake update --flake "''${NIXOS_FLAKE:-/etc/nixos}"
just rebuild
}
update_home() {
nix flake update --flake "''${XDG_CONFIG_HOME:-$HOME/.config}/home-manager"
just switch
}
case "{{target}}" in
system) update_system ;;
home) update_home ;;
"") update_system; update_home ;;
*)
echo "usage: just update [system|home] (empty = both)" >&2
exit 1
;;
esac
[no-cd]
init-home:

View file

@ -37,18 +37,43 @@ fi
(( INTERACTIVE )) || return 0
# ---- run-once guard --------------------------------------------------------
# Installed as both loginShellInit (/etc/profile) and interactiveShellInit
# (/etc/bashrc), and /etc/profile sources /etc/bashrc, so a login shell would run
# this twice and register starship's hooks twice. Not exported: child shells must
# initialise on their own.
if [[ -n ${NANUQSAURUS_SHELL_INIT_DONE:-} ]]; then
log_shell_init "already initialised, skipping"
return 0
fi
NANUQSAURUS_SHELL_INIT_DONE=1
# ---- bash-preexec ----------------------------------------------------------
if [[ -n ${BASH_VERSION:-} && -z ${bash_preexec_imported:-} && -r "@BASHPREEXEC@" ]]; then
# shellcheck disable=SC1090
. "@BASHPREEXEC@"
# Do NOT call __bp_install here. bash-preexec must install on the FIRST prompt,
# after starship/atuin/zoxide/ghostty have modified PROMPT_COMMAND, so that
# __bp_interactive_mode stays the LAST PROMPT_COMMAND entry. Installing eagerly
# lets later hooks land after it and silently breaks preexec (atuin recording).
log_shell_init "bash-preexec loaded"
fi
# bash-preexec arms its DEBUG trap from __bp_interactive_mode, which it appends to
# the END of PROMPT_COMMAND -- but its lazy installer runs in the MIDDLE of the
# first prompt, because zoxide (below) and ghostty (~/.bashrc) append their hooks
# after it. Those hooks then disarm the trap again, so the first command of every
# session never reaches preexec and atuin never records it. PS0 is expanded once
# per interactive command, before the DEBUG trap, so arming there is independent of
# PROMPT_COMMAND ordering. Needs the non-forking ${ ...; } funsub (bash >= 5.3);
# older bash keeps the previous behaviour.
if [[ -n ${bash_preexec_imported:-} ]] &&
((BASH_VERSINFO[0] > 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3))); then
# shellcheck disable=SC2016
__nanuq_bp_arm='${ __bp_preexec_interactive_mode=on; }'
[[ ${PS0-} == *"$__nanuq_bp_arm"* ]] || PS0=$__nanuq_bp_arm${PS0-}
unset __nanuq_bp_arm
log_shell_init "bash-preexec PS0 arming enabled"
fi
# ---- starship --------------------------------------------------------------
if have @STARSHIP@; then
@ -57,8 +82,7 @@ if have @STARSHIP@; then
*/bash) eval "$(@STARSHIP@ init bash)" ;;
*/zsh) eval "$(@STARSHIP@ init zsh)" ;;
esac
# starship's bash init registers starship_precmd/starship_preexec_all with
# bash-preexec directly; no manual PROMPT_COMMAND wiring needed.
# registers starship_precmd/starship_preexec_all with bash-preexec directly
else
log_shell_init "starship skipped"
fi
@ -77,8 +101,7 @@ if have @ATUIN@; then
*/bash) eval "$(@ATUIN@ init bash)" ;;
*/zsh) eval "$(@ATUIN@ init zsh)" ;;
esac
# atuin's init registers __atuin_preexec/__atuin_precmd with bash-preexec
# itself; manual array wiring only caused duplicate hook entries.
# registers __atuin_preexec/__atuin_precmd with bash-preexec itself
else
log_shell_init "atuin skipped"
fi
@ -91,9 +114,7 @@ if have zoxide; then
*/bash) eval "$(zoxide init bash)" ;;
*/zsh) eval "$(zoxide init zsh)" ;;
esac
# zoxide's bash init hooks into bash-preexec (precmd_functions) when it is
# present; manual PROMPT_COMMAND wiring only pushed hooks past
# __bp_interactive_mode and broke preexec ordering.
# appends __zoxide_hook to PROMPT_COMMAND; see the PS0 note above
else
log_shell_init "zoxide skipped"
fi