Compare commits
10 commits
1565c4cb5c
...
eb9d7fb9b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb9d7fb9b8 | ||
|
|
9f28569fef | ||
|
|
3f29ad6cec | ||
|
|
228fe626b5 | ||
|
|
d1321cf7ca | ||
|
|
17cce973fc | ||
|
|
72941092d2 | ||
|
|
2f9293f698 | ||
|
|
86b5c2422e | ||
|
|
be7ecfc0ea |
14 changed files with 360 additions and 506 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,3 +4,6 @@ result
|
|||
.DS_Store
|
||||
hosts/*-hardware.nix
|
||||
hosts/local-*.nix
|
||||
|
||||
# editor / assistant local config
|
||||
.claude/
|
||||
|
|
|
|||
310
agents.md
310
agents.md
|
|
@ -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`
|
||||
|
|
@ -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
95
flake.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
208
laptop.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# Install Nanuqsaurus On An Empty Partition (No Full-Disk Wipe)
|
||||
|
||||
This repo’s `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 repo’s 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 repo’s `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 repo’s 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`).
|
||||
|
|
@ -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)
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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 = "/";
|
||||
|
|
|
|||
|
|
@ -10,36 +10,50 @@
|
|||
config = lib.mkIf config.nanuqsaurus.impermanence.enable {
|
||||
boot.initrd.supportedFilesystems = [ "btrfs" ];
|
||||
|
||||
boot.initrd.postDeviceCommands = lib.mkAfter ''
|
||||
mkdir -p /mnt
|
||||
mount -t btrfs -o subvol=/ /dev/disk/by-label/nixos /mnt
|
||||
# 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
|
||||
|
||||
if [ ! -d /mnt/root-blank ]; then
|
||||
btrfs subvolume snapshot -r /mnt/root /mnt/root-blank
|
||||
fi
|
||||
|
||||
if [ -d /mnt/root ]; then
|
||||
if [ -d /mnt/root-previous ]; then
|
||||
btrfs subvolume delete /mnt/root-previous
|
||||
if [ ! -d /mnt/root-blank ]; then
|
||||
btrfs subvolume snapshot -r /mnt/root /mnt/root-blank
|
||||
fi
|
||||
btrfs subvolume snapshot /mnt/root /mnt/root-previous
|
||||
|
||||
while true; do
|
||||
subvols="$(btrfs subvolume list -o /mnt/root | awk '{print $9}')"
|
||||
if [ -z "$subvols" ]; then
|
||||
break
|
||||
if [ -d /mnt/root ]; then
|
||||
if [ -d /mnt/root-previous ]; then
|
||||
btrfs subvolume delete /mnt/root-previous
|
||||
fi
|
||||
for subvol in $subvols; do
|
||||
btrfs subvolume delete "/mnt/$subvol"
|
||||
btrfs subvolume snapshot /mnt/root /mnt/root-previous
|
||||
|
||||
while true; do
|
||||
subvols="$(btrfs subvolume list -o /mnt/root | cut -f9 -d' ')"
|
||||
if [ -z "$subvols" ]; then
|
||||
break
|
||||
fi
|
||||
for subvol in $subvols; do
|
||||
btrfs subvolume delete "/mnt/$subvol"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
btrfs subvolume delete /mnt/root
|
||||
fi
|
||||
btrfs subvolume delete /mnt/root
|
||||
fi
|
||||
|
||||
btrfs subvolume snapshot /mnt/root-blank /mnt/root
|
||||
umount /mnt
|
||||
'';
|
||||
btrfs subvolume snapshot /mnt/root-blank /mnt/root
|
||||
umount /mnt
|
||||
'';
|
||||
};
|
||||
|
||||
fileSystems."/persist".neededForBoot = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,29 @@ let
|
|||
nix-collect-garbage -d
|
||||
|
||||
[no-cd]
|
||||
update:
|
||||
sudo nix flake update --flake "''${NIXOS_FLAKE:-/etc/nixos}"
|
||||
just rebuild
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue